]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #107316 - ChrisDenton:snap, r=oli-obk
authorYuki Okushi <jtitor@2k36.org>
Fri, 27 Jan 2023 15:23:13 +0000 (00:23 +0900)
committerGitHub <noreply@github.com>
Fri, 27 Jan 2023 15:23:13 +0000 (00:23 +0900)
Update snap from `1.0.1` to `1.1.0`

As spotted by `@mejrs,` snap 1.0.1 emits a future compatibility warning. This was fixed in https://github.com/BurntSushi/rust-snappy/pull/39

286 files changed:
Cargo.lock
compiler/rustc_abi/src/lib.rs
compiler/rustc_ast/Cargo.toml
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/format.rs [new file with mode: 0644]
compiler/rustc_ast/src/lib.rs
compiler/rustc_ast/src/mut_visit.rs
compiler/rustc_ast/src/util/parser.rs
compiler/rustc_ast/src/util/unicode.rs
compiler/rustc_ast/src/visit.rs
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_ast_lowering/src/format.rs [new file with mode: 0644]
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_ast_pretty/Cargo.toml
compiler/rustc_ast_pretty/src/pprust/state/expr.rs
compiler/rustc_borrowck/src/region_infer/opaque_types.rs
compiler/rustc_builtin_macros/src/assert/context.rs
compiler/rustc_builtin_macros/src/format.rs
compiler/rustc_builtin_macros/src/format/ast.rs [deleted file]
compiler/rustc_builtin_macros/src/format/expand.rs [deleted file]
compiler/rustc_codegen_cranelift/.cirrus.yml
compiler/rustc_codegen_cranelift/.github/workflows/main.yml
compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml [deleted file]
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/bench.rs [new file with mode: 0644]
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
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/usage.txt [new file with mode: 0644]
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/patches/0001-portable-simd-Disable-unsupported-tests.patch [deleted file]
compiler/rustc_codegen_cranelift/patches/0022-sysroot-Disable-not-compiling-tests.patch
compiler/rustc_codegen_cranelift/rust-toolchain
compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs
compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs
compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs
compiler/rustc_codegen_cranelift/scripts/rustup.sh
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/base.rs
compiler/rustc_codegen_cranelift/src/common.rs
compiler/rustc_codegen_cranelift/src/cranelift_native.rs [new file with mode: 0644]
compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
compiler/rustc_codegen_cranelift/src/driver/aot.rs
compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
compiler/rustc_codegen_cranelift/src/lib.rs
compiler/rustc_codegen_cranelift/src/main_shim.rs
compiler/rustc_codegen_cranelift/src/optimize/peephole.rs
compiler/rustc_codegen_cranelift/src/value_and_place.rs
compiler/rustc_codegen_cranelift/y.rs
compiler/rustc_codegen_gcc/src/builder.rs
compiler/rustc_codegen_gcc/src/common.rs
compiler/rustc_codegen_gcc/src/consts.rs
compiler/rustc_codegen_gcc/src/type_of.rs
compiler/rustc_codegen_llvm/src/asm.rs
compiler/rustc_codegen_llvm/src/builder.rs
compiler/rustc_codegen_llvm/src/common.rs
compiler/rustc_codegen_llvm/src/consts.rs
compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
compiler/rustc_codegen_llvm/src/errors.rs
compiler/rustc_codegen_llvm/src/intrinsic.rs
compiler/rustc_codegen_llvm/src/type_of.rs
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/mir/block.rs
compiler/rustc_codegen_ssa/src/mir/mod.rs
compiler/rustc_codegen_ssa/src/mir/place.rs
compiler/rustc_const_eval/src/interpret/intrinsics.rs
compiler/rustc_const_eval/src/interpret/operand.rs
compiler/rustc_const_eval/src/lib.rs
compiler/rustc_const_eval/src/transform/validate.rs
compiler/rustc_const_eval/src/util/might_permit_raw_init.rs
compiler/rustc_data_structures/src/obligation_forest/mod.rs
compiler/rustc_driver/src/lib.rs
compiler/rustc_driver/src/pretty.rs
compiler/rustc_error_messages/locales/en-US/borrowck.ftl
compiler/rustc_error_messages/locales/en-US/codegen_llvm.ftl
compiler/rustc_error_messages/locales/en-US/infer.ftl
compiler/rustc_error_messages/locales/en-US/mir_build.ftl
compiler/rustc_error_messages/locales/en-US/passes.ftl
compiler/rustc_error_messages/src/lib.rs
compiler/rustc_hir/src/hir.rs
compiler/rustc_hir/src/lang_items.rs
compiler/rustc_hir_typeck/src/demand.rs
compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
compiler/rustc_hir_typeck/src/intrinsicck.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs [new file with mode: 0644]
compiler/rustc_infer/src/infer/error_reporting/suggest.rs
compiler/rustc_interface/src/passes.rs
compiler/rustc_interface/src/queries.rs
compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_middle/src/lib.rs
compiler/rustc_middle/src/mir/interpret/mod.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/ty/assoc.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/context/tls.rs [new file with mode: 0644]
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_middle/src/ty/query.rs
compiler/rustc_middle/src/ty/structural_impls.rs
compiler/rustc_middle/src/ty/util.rs
compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
compiler/rustc_mir_build/src/errors.rs
compiler/rustc_mir_build/src/thir/pattern/check_match.rs
compiler/rustc_mir_transform/src/const_goto.rs
compiler/rustc_mir_transform/src/instcombine.rs
compiler/rustc_parse/src/parser/diagnostics.rs
compiler/rustc_parse/src/parser/pat.rs
compiler/rustc_parse/src/parser/ty.rs
compiler/rustc_parse_format/src/lib.rs
compiler/rustc_parse_format/src/tests.rs
compiler/rustc_passes/src/check_attr.rs
compiler/rustc_passes/src/check_const.rs
compiler/rustc_passes/src/errors.rs
compiler/rustc_passes/src/hir_stats.rs
compiler/rustc_resolve/src/late/diagnostics.rs
compiler/rustc_session/src/config.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_target/src/abi/call/loongarch.rs
compiler/rustc_target/src/abi/call/mod.rs
compiler/rustc_target/src/abi/call/riscv.rs
compiler/rustc_target/src/abi/call/sparc64.rs
compiler/rustc_target/src/abi/call/x86_64.rs
compiler/rustc_target/src/abi/mod.rs
compiler/rustc_trait_selection/src/solve/assembly.rs
compiler/rustc_trait_selection/src/solve/fulfill.rs
compiler/rustc_trait_selection/src/solve/mod.rs
compiler/rustc_trait_selection/src/solve/project_goals.rs
compiler/rustc_trait_selection/src/solve/trait_goals.rs
compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs
compiler/rustc_trait_selection/src/traits/wf.rs
compiler/rustc_ty_utils/src/abi.rs
compiler/rustc_ty_utils/src/layout.rs
library/core/src/cell.rs
library/core/src/fmt/mod.rs
library/core/src/fmt/rt/v1.rs
library/core/src/intrinsics/mir.rs
library/core/src/sync/atomic.rs
library/proc_macro/src/lib.rs
library/std/src/sync/mpmc/array.rs
library/std/src/sync/mpmc/utils.rs
library/std/src/sys/unix/thread_local_dtor.rs
library/std/tests/run-time-detect.rs
library/stdarch
src/bootstrap/bin/main.rs
src/bootstrap/config.rs
src/bootstrap/config/tests.rs
src/bootstrap/native.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/clean/utils.rs
src/librustdoc/core.rs
src/librustdoc/doctest.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render/print_item.rs
src/librustdoc/html/static/css/rustdoc.css
src/librustdoc/lib.rs
src/librustdoc/passes/calculate_doc_coverage.rs
src/librustdoc/passes/check_doc_test_visibility.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/collect_intra_doc_links/early.rs
src/librustdoc/passes/lint/check_code_block_syntax.rs
src/librustdoc/passes/propagate_doc_cfg.rs
src/librustdoc/visit_ast.rs
src/librustdoc/visit_lib.rs
src/tools/clippy/clippy_lints/src/format_args.rs
src/tools/clippy/clippy_utils/src/macros.rs
src/tools/clippy/clippy_utils/src/sugg.rs
src/tools/rustfmt/src/expr.rs
src/tools/rustfmt/src/utils.rs
src/tools/tidy/src/deps.rs
tests/codegen/avr/avr-func-addrspace.rs
tests/mir-opt/building/custom/arrays.arrays.built.after.mir [new file with mode: 0644]
tests/mir-opt/building/custom/arrays.rs [new file with mode: 0644]
tests/mir-opt/building/custom/enums.rs
tests/mir-opt/building/custom/enums.set_discr.built.after.mir
tests/mir-opt/building/custom/operators.f.built.after.mir [new file with mode: 0644]
tests/mir-opt/building/custom/operators.rs [new file with mode: 0644]
tests/mir-opt/intrinsic_asserts.generic.InstCombine.diff [new file with mode: 0644]
tests/mir-opt/intrinsic_asserts.panics.InstCombine.diff [new file with mode: 0644]
tests/mir-opt/intrinsic_asserts.removable.InstCombine.diff [new file with mode: 0644]
tests/mir-opt/intrinsic_asserts.rs [new file with mode: 0644]
tests/pretty/dollar-crate.pp
tests/pretty/issue-4264.pp
tests/run-make-fulldeps/split-debuginfo/Makefile
tests/run-make/overwrite-input/Makefile [new file with mode: 0644]
tests/run-make/overwrite-input/file.stderr [new file with mode: 0644]
tests/run-make/overwrite-input/folder.stderr [new file with mode: 0644]
tests/run-make/overwrite-input/main.rs [new file with mode: 0644]
tests/run-make/overwrite-input/main.stderr [new file with mode: 0644]
tests/rustdoc-gui/label-next-to-symbol.goml
tests/rustdoc-gui/module-items-font.goml
tests/rustdoc-gui/unsafe-fn.goml
tests/rustdoc/cfg_doc_reexport.rs
tests/rustdoc/deprecated.rs
tests/rustdoc/doc-cfg.rs
tests/rustdoc/duplicate-cfg.rs
tests/rustdoc/glob-shadowing.rs
tests/rustdoc/inline_cross/macros.rs
tests/rustdoc/issue-32374.rs
tests/rustdoc/issue-55364.rs
tests/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline-last-item.rs
tests/rustdoc/issue-83375-multiple-mods-w-same-name-doc-inline.rs
tests/rustdoc/issue-95873.rs
tests/rustdoc/issue-99221-multiple-structs-w-same-name.rs
tests/rustdoc/issue-99734-multiple-foreigns-w-same-name.rs
tests/rustdoc/issue-99734-multiple-mods-w-same-name.rs
tests/rustdoc/playground-arg.rs
tests/rustdoc/playground.rs
tests/rustdoc/reexport-check.rs
tests/ui/associated-types/defaults-in-other-trait-items.rs
tests/ui/associated-types/defaults-in-other-trait-items.stderr
tests/ui/associated-types/issue-26681.stderr
tests/ui/attributes/key-value-expansion.stderr
tests/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.rs [new file with mode: 0644]
tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.stderr [new file with mode: 0644]
tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs [new file with mode: 0644]
tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr [new file with mode: 0644]
tests/ui/fn/fn-compare-mismatch.stderr
tests/ui/fn/fn-item-type.stderr
tests/ui/fn/fn-pointer-mismatch.stderr
tests/ui/io-checks/inaccessbile-temp-dir.rs [new file with mode: 0644]
tests/ui/io-checks/inaccessbile-temp-dir.stderr [new file with mode: 0644]
tests/ui/io-checks/non-ice-error-on-worker-io-fail.rs [new file with mode: 0644]
tests/ui/io-checks/non-ice-error-on-worker-io-fail.stderr [new file with mode: 0644]
tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout
tests/ui/non-ice-error-on-worker-io-fail.rs [deleted file]
tests/ui/non-ice-error-on-worker-io-fail.stderr [deleted file]
tests/ui/parser/anon-enums.rs [new file with mode: 0644]
tests/ui/parser/anon-enums.stderr [new file with mode: 0644]
tests/ui/parser/fake-anon-enums-in-macros.rs [new file with mode: 0644]
tests/ui/parser/issues/issue-87086-colon-path-sep.rs
tests/ui/parser/issues/issue-87086-colon-path-sep.stderr
tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
tests/ui/proc-macro/allowed-signatures.rs [new file with mode: 0644]
tests/ui/proc-macro/proc-macro-abi.rs [new file with mode: 0644]
tests/ui/proc-macro/proc-macro-abi.stderr [new file with mode: 0644]
tests/ui/proc-macro/signature-proc-macro-attribute.rs [new file with mode: 0644]
tests/ui/proc-macro/signature-proc-macro-attribute.stderr [new file with mode: 0644]
tests/ui/proc-macro/signature-proc-macro-derive.rs [new file with mode: 0644]
tests/ui/proc-macro/signature-proc-macro-derive.stderr [new file with mode: 0644]
tests/ui/proc-macro/signature-proc-macro.rs [new file with mode: 0644]
tests/ui/proc-macro/signature-proc-macro.stderr [new file with mode: 0644]
tests/ui/proc-macro/signature.rs
tests/ui/proc-macro/signature.stderr
tests/ui/self/arbitrary_self_types_pointers_and_wrappers.rs
tests/ui/suggestions/assoc-const-without-self.rs [new file with mode: 0644]
tests/ui/suggestions/assoc-const-without-self.stderr [new file with mode: 0644]
tests/ui/suggestions/ref-pattern-binding.stderr
tests/ui/traits/new-solver/async.fail.stderr [new file with mode: 0644]
tests/ui/traits/new-solver/async.rs [new file with mode: 0644]
tests/ui/traits/new-solver/generator.fail.stderr [new file with mode: 0644]
tests/ui/traits/new-solver/generator.rs [new file with mode: 0644]
tests/ui/type-alias-impl-trait/bounds-are-checked.rs
tests/ui/type-alias-impl-trait/bounds-are-checked.stderr
tests/ui/type-alias-impl-trait/generic_nondefining_use.rs
tests/ui/type-alias-impl-trait/generic_nondefining_use.stderr
tests/ui/typeck/bad-type-in-vec-push.rs [new file with mode: 0644]
tests/ui/typeck/bad-type-in-vec-push.stderr [new file with mode: 0644]
triagebot.toml

index c81bf9fddf607ddefc00d102864f8802955e32b1..46dd039728025d70bc10ad9e55ed926cec988c83 100644 (file)
@@ -351,7 +351,7 @@ dependencies = [
  "cargo-test-macro",
  "cargo-test-support",
  "cargo-util",
- "clap 4.1.3",
+ "clap 4.1.4",
  "crates-io",
  "curl",
  "curl-sys",
@@ -655,9 +655,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.1.3"
+version = "4.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8d93d855ce6a0aa87b8473ef9169482f40abaa2e9e0993024c35c902cbd5920"
+checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76"
 dependencies = [
  "bitflags",
  "clap_derive 4.1.0",
@@ -675,7 +675,7 @@ version = "4.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "10861370d2ba66b0f5989f83ebf35db6421713fd92351790e7fdd6c36774c56b"
 dependencies = [
- "clap 4.1.3",
+ "clap 4.1.4",
 ]
 
 [[package]]
@@ -2294,7 +2294,7 @@ name = "jsondoclint"
 version = "0.1.0"
 dependencies = [
  "anyhow",
- "clap 4.1.3",
+ "clap 4.1.4",
  "fs-err",
  "rustdoc-json-types",
  "serde",
@@ -2557,7 +2557,7 @@ dependencies = [
  "ammonia",
  "anyhow",
  "chrono",
- "clap 4.1.3",
+ "clap 4.1.4",
  "clap_complete",
  "elasticlunr-rs",
  "env_logger 0.10.0",
@@ -3528,7 +3528,7 @@ dependencies = [
 name = "rustbook"
 version = "0.1.0"
 dependencies = [
- "clap 4.1.3",
+ "clap 4.1.4",
  "env_logger 0.7.1",
  "mdbook",
 ]
@@ -3672,6 +3672,7 @@ name = "rustc_ast"
 version = "0.0.0"
 dependencies = [
  "bitflags",
+ "memchr",
  "rustc_data_structures",
  "rustc_index",
  "rustc_lexer",
@@ -3729,6 +3730,7 @@ name = "rustc_ast_pretty"
 version = "0.0.0"
 dependencies = [
  "rustc_ast",
+ "rustc_parse_format",
  "rustc_span",
 ]
 
index f4cb459f32fddee1bcc78c465ae6916b8a92736e..fe65ad9c6cb0e9bde1aaff6e4801ef2f2b8c964a 100644 (file)
@@ -267,6 +267,9 @@ pub fn parse_from_llvm_datalayout_string<'a>(
                 ["a", ref a @ ..] => dl.aggregate_align = align(a, "a")?,
                 ["f32", ref a @ ..] => dl.f32_align = align(a, "f32")?,
                 ["f64", ref a @ ..] => dl.f64_align = align(a, "f64")?,
+                // FIXME(erikdesjardins): we should be parsing nonzero address spaces
+                // this will require replacing TargetDataLayout::{pointer_size,pointer_align}
+                // with e.g. `fn pointer_size_in(AddressSpace)`
                 [p @ "p", s, ref a @ ..] | [p @ "p0", s, ref a @ ..] => {
                     dl.pointer_size = size(s, p)?;
                     dl.pointer_align = align(a, p)?;
@@ -861,7 +864,7 @@ pub enum Primitive {
     Int(Integer, bool),
     F32,
     F64,
-    Pointer,
+    Pointer(AddressSpace),
 }
 
 impl Primitive {
@@ -872,7 +875,10 @@ pub fn size<C: HasDataLayout>(self, cx: &C) -> Size {
             Int(i, _) => i.size(),
             F32 => Size::from_bits(32),
             F64 => Size::from_bits(64),
-            Pointer => dl.pointer_size,
+            // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
+            // different address spaces can have different sizes
+            // (but TargetDataLayout doesn't currently parse that part of the DL string)
+            Pointer(_) => dl.pointer_size,
         }
     }
 
@@ -883,26 +889,12 @@ pub fn align<C: HasDataLayout>(self, cx: &C) -> AbiAndPrefAlign {
             Int(i, _) => i.align(dl),
             F32 => dl.f32_align,
             F64 => dl.f64_align,
-            Pointer => dl.pointer_align,
+            // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
+            // different address spaces can have different alignments
+            // (but TargetDataLayout doesn't currently parse that part of the DL string)
+            Pointer(_) => dl.pointer_align,
         }
     }
-
-    // FIXME(eddyb) remove, it's trivial thanks to `matches!`.
-    #[inline]
-    pub fn is_float(self) -> bool {
-        matches!(self, F32 | F64)
-    }
-
-    // FIXME(eddyb) remove, it's completely unused.
-    #[inline]
-    pub fn is_int(self) -> bool {
-        matches!(self, Int(..))
-    }
-
-    #[inline]
-    pub fn is_ptr(self) -> bool {
-        matches!(self, Pointer)
-    }
 }
 
 /// Inclusive wrap-around range of valid values, that is, if
@@ -1188,7 +1180,8 @@ pub fn index_by_increasing_offset<'a>(&'a self) -> impl Iterator<Item = usize> +
 /// An identifier that specifies the address space that some operation
 /// should operate on. Special address spaces have an effect on code generation,
 /// depending on the target and the address spaces it implements.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
 pub struct AddressSpace(pub u32);
 
 impl AddressSpace {
@@ -1468,7 +1461,6 @@ pub struct PointeeInfo {
     pub size: Size,
     pub align: Align,
     pub safe: Option<PointerKind>,
-    pub address_space: AddressSpace,
 }
 
 /// Used in `might_permit_raw_init` to indicate the kind of initialisation
index 9253b7e6891a25db4592b74ce72c513da14482bb..10d7fa1db605a7dc7c5e70b53fe175c1f60ff185 100644 (file)
@@ -7,6 +7,7 @@ edition = "2021"
 
 [dependencies]
 bitflags = "1.2.1"
+memchr = "2.5.0"
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_index = { path = "../rustc_index" }
 rustc_lexer = { path = "../rustc_lexer" }
index 9317579f70dd5967cb5e80382c8cab541c58ecea..8ad3270c5103ec24cbd11429b4f7cd7984fba6fd 100644 (file)
@@ -18,6 +18,7 @@
 //! - [`Attribute`]: Metadata associated with item.
 //! - [`UnOp`], [`BinOp`], and [`BinOpKind`]: Unary and binary operators.
 
+pub use crate::format::*;
 pub use crate::util::parser::ExprPrecedence;
 pub use GenericArgs::*;
 pub use UnsafeSource::*;
@@ -1269,6 +1270,7 @@ pub fn precedence(&self) -> ExprPrecedence {
             ExprKind::Try(..) => ExprPrecedence::Try,
             ExprKind::Yield(..) => ExprPrecedence::Yield,
             ExprKind::Yeet(..) => ExprPrecedence::Yeet,
+            ExprKind::FormatArgs(..) => ExprPrecedence::FormatArgs,
             ExprKind::Err => ExprPrecedence::Err,
         }
     }
@@ -1499,6 +1501,9 @@ pub enum ExprKind {
     /// with a `ByteStr` literal.
     IncludedBytes(Lrc<[u8]>),
 
+    /// A `format_args!()` expression.
+    FormatArgs(P<FormatArgs>),
+
     /// Placeholder for an expression that wasn't syntactically well formed in some way.
     Err,
 }
diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs
new file mode 100644 (file)
index 0000000..d021bea
--- /dev/null
@@ -0,0 +1,272 @@
+use crate::ptr::P;
+use crate::Expr;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::Span;
+
+// Definitions:
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+// └──────────────────────────────────────────────┘
+//                     FormatArgs
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+//                                     └─────────┘
+//                                      argument
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+//              └───────────────────┘
+//                     template
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+//               └────┘└─────────┘└┘
+//                      pieces
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+//               └────┘           └┘
+//                   literal pieces
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+//                     └─────────┘
+//                     placeholder
+//
+// format_args!("hello {abc:.xyz$}!!", abc="world");
+//                      └─┘  └─┘
+//                      positions (could be names, numbers, empty, or `*`)
+
+/// (Parsed) format args.
+///
+/// Basically the "AST" for a complete `format_args!()`.
+///
+/// E.g., `format_args!("hello {name}");`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct FormatArgs {
+    pub span: Span,
+    pub template: Vec<FormatArgsPiece>,
+    pub arguments: FormatArguments,
+}
+
+/// A piece of a format template string.
+///
+/// E.g. "hello" or "{name}".
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum FormatArgsPiece {
+    Literal(Symbol),
+    Placeholder(FormatPlaceholder),
+}
+
+/// The arguments to format_args!().
+///
+/// E.g. `1, 2, name="ferris", n=3`,
+/// but also implicit captured arguments like `x` in `format_args!("{x}")`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct FormatArguments {
+    arguments: Vec<FormatArgument>,
+    num_unnamed_args: usize,
+    num_explicit_args: usize,
+    names: FxHashMap<Symbol, usize>,
+}
+
+// FIXME: Rustdoc has trouble proving Send/Sync for this. See #106930.
+#[cfg(parallel_compiler)]
+unsafe impl Sync for FormatArguments {}
+#[cfg(parallel_compiler)]
+unsafe impl Send for FormatArguments {}
+
+impl FormatArguments {
+    pub fn new() -> Self {
+        Self {
+            arguments: Vec::new(),
+            names: FxHashMap::default(),
+            num_unnamed_args: 0,
+            num_explicit_args: 0,
+        }
+    }
+
+    pub fn add(&mut self, arg: FormatArgument) -> usize {
+        let index = self.arguments.len();
+        if let Some(name) = arg.kind.ident() {
+            self.names.insert(name.name, index);
+        } else if self.names.is_empty() {
+            // Only count the unnamed args before the first named arg.
+            // (Any later ones are errors.)
+            self.num_unnamed_args += 1;
+        }
+        if !matches!(arg.kind, FormatArgumentKind::Captured(..)) {
+            // This is an explicit argument.
+            // Make sure that all arguments so far are explcit.
+            assert_eq!(
+                self.num_explicit_args,
+                self.arguments.len(),
+                "captured arguments must be added last"
+            );
+            self.num_explicit_args += 1;
+        }
+        self.arguments.push(arg);
+        index
+    }
+
+    pub fn by_name(&self, name: Symbol) -> Option<(usize, &FormatArgument)> {
+        let i = *self.names.get(&name)?;
+        Some((i, &self.arguments[i]))
+    }
+
+    pub fn by_index(&self, i: usize) -> Option<&FormatArgument> {
+        (i < self.num_explicit_args).then(|| &self.arguments[i])
+    }
+
+    pub fn unnamed_args(&self) -> &[FormatArgument] {
+        &self.arguments[..self.num_unnamed_args]
+    }
+
+    pub fn named_args(&self) -> &[FormatArgument] {
+        &self.arguments[self.num_unnamed_args..self.num_explicit_args]
+    }
+
+    pub fn explicit_args(&self) -> &[FormatArgument] {
+        &self.arguments[..self.num_explicit_args]
+    }
+
+    pub fn all_args(&self) -> &[FormatArgument] {
+        &self.arguments[..]
+    }
+
+    pub fn all_args_mut(&mut self) -> &mut [FormatArgument] {
+        &mut self.arguments[..]
+    }
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct FormatArgument {
+    pub kind: FormatArgumentKind,
+    pub expr: P<Expr>,
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum FormatArgumentKind {
+    /// `format_args(…, arg)`
+    Normal,
+    /// `format_args(…, arg = 1)`
+    Named(Ident),
+    /// `format_args("… {arg} …")`
+    Captured(Ident),
+}
+
+impl FormatArgumentKind {
+    pub fn ident(&self) -> Option<Ident> {
+        match self {
+            &Self::Normal => None,
+            &Self::Named(id) => Some(id),
+            &Self::Captured(id) => Some(id),
+        }
+    }
+}
+
+#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
+pub struct FormatPlaceholder {
+    /// Index into [`FormatArgs::arguments`].
+    pub argument: FormatArgPosition,
+    /// The span inside the format string for the full `{…}` placeholder.
+    pub span: Option<Span>,
+    /// `{}`, `{:?}`, or `{:x}`, etc.
+    pub format_trait: FormatTrait,
+    /// `{}` or `{:.5}` or `{:-^20}`, etc.
+    pub format_options: FormatOptions,
+}
+
+#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
+pub struct FormatArgPosition {
+    /// Which argument this position refers to (Ok),
+    /// or would've referred to if it existed (Err).
+    pub index: Result<usize, usize>,
+    /// What kind of position this is. See [`FormatArgPositionKind`].
+    pub kind: FormatArgPositionKind,
+    /// The span of the name or number.
+    pub span: Option<Span>,
+}
+
+#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
+pub enum FormatArgPositionKind {
+    /// `{}` or `{:.*}`
+    Implicit,
+    /// `{1}` or `{:1$}` or `{:.1$}`
+    Number,
+    /// `{a}` or `{:a$}` or `{:.a$}`
+    Named,
+}
+
+#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq, Hash)]
+pub enum FormatTrait {
+    /// `{}`
+    Display,
+    /// `{:?}`
+    Debug,
+    /// `{:e}`
+    LowerExp,
+    /// `{:E}`
+    UpperExp,
+    /// `{:o}`
+    Octal,
+    /// `{:p}`
+    Pointer,
+    /// `{:b}`
+    Binary,
+    /// `{:x}`
+    LowerHex,
+    /// `{:X}`
+    UpperHex,
+}
+
+#[derive(Clone, Encodable, Decodable, Default, Debug, PartialEq, Eq)]
+pub struct FormatOptions {
+    /// The width. E.g. `{:5}` or `{:width$}`.
+    pub width: Option<FormatCount>,
+    /// The precision. E.g. `{:.5}` or `{:.precision$}`.
+    pub precision: Option<FormatCount>,
+    /// The alignment. E.g. `{:>}` or `{:<}` or `{:^}`.
+    pub alignment: Option<FormatAlignment>,
+    /// The fill character. E.g. the `.` in `{:.>10}`.
+    pub fill: Option<char>,
+    /// The `+` or `-` flag.
+    pub sign: Option<FormatSign>,
+    /// The `#` flag.
+    pub alternate: bool,
+    /// The `0` flag. E.g. the `0` in `{:02x}`.
+    pub zero_pad: bool,
+    /// The `x` or `X` flag (for `Debug` only). E.g. the `x` in `{:x?}`.
+    pub debug_hex: Option<FormatDebugHex>,
+}
+
+#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
+pub enum FormatSign {
+    /// The `+` flag.
+    Plus,
+    /// The `-` flag.
+    Minus,
+}
+
+#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
+pub enum FormatDebugHex {
+    /// The `x` flag in `{:x?}`.
+    Lower,
+    /// The `X` flag in `{:X?}`.
+    Upper,
+}
+
+#[derive(Copy, Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
+pub enum FormatAlignment {
+    /// `{:<}`
+    Left,
+    /// `{:>}`
+    Right,
+    /// `{:^}`
+    Center,
+}
+
+#[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)]
+pub enum FormatCount {
+    /// `{:5}` or `{:.5}`
+    Literal(usize),
+    /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc.
+    Argument(FormatArgPosition),
+}
index 9c1dfeb1a61428920e20e4ac69f61e9913701094..23c32fa96ca449e40f705596d897a9a6c0d14f87 100644 (file)
@@ -16,7 +16,6 @@
 #![feature(let_chains)]
 #![feature(min_specialization)]
 #![feature(negative_impls)]
-#![feature(slice_internals)]
 #![feature(stmt_expr_attributes)]
 #![recursion_limit = "256"]
 #![deny(rustc::untranslatable_diagnostic)]
@@ -42,6 +41,7 @@ pub mod util {
 pub mod attr;
 pub mod entry;
 pub mod expand;
+pub mod format;
 pub mod mut_visit;
 pub mod node_id;
 pub mod ptr;
@@ -51,6 +51,7 @@ pub mod util {
 
 pub use self::ast::*;
 pub use self::ast_traits::{AstDeref, AstNodeWrapper, HasAttrs, HasNodeId, HasSpan, HasTokens};
+pub use self::format::*;
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 
index 77f342d1eb322efe2a35deb211006e6408a243b5..1dd62626b8f5e33607a4e87a362b4875997128ef 100644 (file)
@@ -297,6 +297,10 @@ fn visit_inline_asm(&mut self, asm: &mut InlineAsm) {
     fn visit_inline_asm_sym(&mut self, sym: &mut InlineAsmSym) {
         noop_visit_inline_asm_sym(sym, self)
     }
+
+    fn visit_format_args(&mut self, fmt: &mut FormatArgs) {
+        noop_visit_format_args(fmt, self)
+    }
 }
 
 /// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
@@ -1284,6 +1288,15 @@ pub fn noop_visit_inline_asm_sym<T: MutVisitor>(
     vis.visit_path(path);
 }
 
+pub fn noop_visit_format_args<T: MutVisitor>(fmt: &mut FormatArgs, vis: &mut T) {
+    for arg in fmt.arguments.all_args_mut() {
+        if let FormatArgumentKind::Named(name) = &mut arg.kind {
+            vis.visit_ident(name);
+        }
+        vis.visit_expr(&mut arg.expr);
+    }
+}
+
 pub fn noop_visit_expr<T: MutVisitor>(
     Expr { kind, id, span, attrs, tokens }: &mut Expr,
     vis: &mut T,
@@ -1425,6 +1438,7 @@ pub fn noop_visit_expr<T: MutVisitor>(
             visit_opt(expr, |expr| vis.visit_expr(expr));
         }
         ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm),
+        ExprKind::FormatArgs(fmt) => vis.visit_format_args(fmt),
         ExprKind::MacCall(mac) => vis.visit_mac_call(mac),
         ExprKind::Struct(se) => {
             let StructExpr { qself, path, fields, rest } = se.deref_mut();
index 4f7099c7be8a6561492a22b210643768b9db4a2a..81efdaa44b365a3979187d37a540640636784a4f 100644 (file)
@@ -271,6 +271,7 @@ pub enum ExprPrecedence {
     Try,
     InlineAsm,
     Mac,
+    FormatArgs,
 
     Array,
     Repeat,
@@ -335,7 +336,8 @@ pub fn order(self) -> i8 {
             | ExprPrecedence::Index
             | ExprPrecedence::Try
             | ExprPrecedence::InlineAsm
-            | ExprPrecedence::Mac => PREC_POSTFIX,
+            | ExprPrecedence::Mac
+            | ExprPrecedence::FormatArgs => PREC_POSTFIX,
 
             // Never need parens
             ExprPrecedence::Array
index 0eae791b25e1c66e8da0b93bdfefa0ce7c5585bb..6f57d66b2273a2cf4421d42f8057c4290dfc653e 100644 (file)
@@ -17,7 +17,7 @@ pub fn contains_text_flow_control_chars(s: &str) -> bool {
     // U+2069 - E2 81 A9
     let mut bytes = s.as_bytes();
     loop {
-        match core::slice::memchr::memchr(0xE2, bytes) {
+        match memchr::memchr(0xE2, bytes) {
             Some(idx) => {
                 // bytes are valid UTF-8 -> E2 must be followed by two bytes
                 let ch = &bytes[idx..idx + 3];
index e8823eff83afe1bab63061dd862a7ed40af53575..e7b2e4b1cb4b072a4d300e0e20b978fa16fb2ee4 100644 (file)
@@ -242,6 +242,9 @@ fn visit_crate(&mut self, krate: &'ast Crate) {
     fn visit_inline_asm(&mut self, asm: &'ast InlineAsm) {
         walk_inline_asm(self, asm)
     }
+    fn visit_format_args(&mut self, fmt: &'ast FormatArgs) {
+        walk_format_args(self, fmt)
+    }
     fn visit_inline_asm_sym(&mut self, sym: &'ast InlineAsmSym) {
         walk_inline_asm_sym(self, sym)
     }
@@ -400,8 +403,8 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) {
             walk_list!(visitor, visit_lifetime, opt_lifetime, LifetimeCtxt::Ref);
             visitor.visit_ty(&mutable_type.ty)
         }
-        TyKind::Tup(tuple_element_types) => {
-            walk_list!(visitor, visit_ty, tuple_element_types);
+        TyKind::Tup(tys) => {
+            walk_list!(visitor, visit_ty, tys);
         }
         TyKind::BareFn(function_declaration) => {
             walk_list!(visitor, visit_generic_param, &function_declaration.generic_params);
@@ -756,6 +759,15 @@ pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>(visitor: &mut V, sym: &'a InlineA
     visitor.visit_path(&sym.path, sym.id);
 }
 
+pub fn walk_format_args<'a, V: Visitor<'a>>(visitor: &mut V, fmt: &'a FormatArgs) {
+    for arg in fmt.arguments.all_args() {
+        if let FormatArgumentKind::Named(name) = arg.kind {
+            visitor.visit_ident(name);
+        }
+        visitor.visit_expr(&arg.expr);
+    }
+}
+
 pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
     walk_list!(visitor, visit_attribute, expression.attrs.iter());
 
@@ -896,6 +908,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
         ExprKind::MacCall(mac) => visitor.visit_mac_call(mac),
         ExprKind::Paren(subexpression) => visitor.visit_expr(subexpression),
         ExprKind::InlineAsm(asm) => visitor.visit_inline_asm(asm),
+        ExprKind::FormatArgs(f) => visitor.visit_format_args(f),
         ExprKind::Yield(optional_expression) => {
             walk_list!(visitor, visit_expr, optional_expression);
         }
index c3611b2f522babd789e589285b1e6359e1f11b18..cc523fe7d08f501b44b9c81e35d307ed179b0423 100644 (file)
@@ -16,7 +16,7 @@
 use rustc_hir::definitions::DefPathData;
 use rustc_session::errors::report_lit_error;
 use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
-use rustc_span::symbol::{sym, Ident};
+use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::DUMMY_SP;
 use thin_vec::thin_vec;
 
@@ -294,6 +294,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                 ExprKind::InlineAsm(asm) => {
                     hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))
                 }
+                ExprKind::FormatArgs(fmt) => self.lower_format_args(e.span, fmt),
                 ExprKind::Struct(se) => {
                     let rest = match &se.rest {
                         StructRest::Base(e) => Some(self.lower_expr(e)),
@@ -1735,7 +1736,7 @@ pub(super) fn expr_drop_temps_mut(
         self.expr(span, hir::ExprKind::DropTemps(expr))
     }
 
-    fn expr_match(
+    pub(super) fn expr_match(
         &mut self,
         span: Span,
         arg: &'hir hir::Expr<'hir>,
@@ -1763,7 +1764,44 @@ fn expr_unit(&mut self, sp: Span) -> &'hir hir::Expr<'hir> {
         self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[])))
     }
 
-    fn expr_call_mut(
+    pub(super) fn expr_usize(&mut self, sp: Span, value: usize) -> hir::Expr<'hir> {
+        self.expr(
+            sp,
+            hir::ExprKind::Lit(hir::Lit {
+                span: sp,
+                node: ast::LitKind::Int(
+                    value as u128,
+                    ast::LitIntType::Unsigned(ast::UintTy::Usize),
+                ),
+            }),
+        )
+    }
+
+    pub(super) fn expr_u32(&mut self, sp: Span, value: u32) -> hir::Expr<'hir> {
+        self.expr(
+            sp,
+            hir::ExprKind::Lit(hir::Lit {
+                span: sp,
+                node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ast::UintTy::U32)),
+            }),
+        )
+    }
+
+    pub(super) fn expr_char(&mut self, sp: Span, value: char) -> hir::Expr<'hir> {
+        self.expr(sp, hir::ExprKind::Lit(hir::Lit { span: sp, node: ast::LitKind::Char(value) }))
+    }
+
+    pub(super) fn expr_str(&mut self, sp: Span, value: Symbol) -> hir::Expr<'hir> {
+        self.expr(
+            sp,
+            hir::ExprKind::Lit(hir::Lit {
+                span: sp,
+                node: ast::LitKind::Str(value, ast::StrStyle::Cooked),
+            }),
+        )
+    }
+
+    pub(super) fn expr_call_mut(
         &mut self,
         span: Span,
         e: &'hir hir::Expr<'hir>,
@@ -1772,7 +1810,7 @@ fn expr_call_mut(
         self.expr(span, hir::ExprKind::Call(e, args))
     }
 
-    fn expr_call(
+    pub(super) fn expr_call(
         &mut self,
         span: Span,
         e: &'hir hir::Expr<'hir>,
@@ -1814,6 +1852,27 @@ fn expr_lang_item_path(
         )
     }
 
+    /// `<LangItem>::name`
+    pub(super) fn expr_lang_item_type_relative(
+        &mut self,
+        span: Span,
+        lang_item: hir::LangItem,
+        name: Symbol,
+    ) -> hir::Expr<'hir> {
+        let path = hir::ExprKind::Path(hir::QPath::TypeRelative(
+            self.arena.alloc(self.ty(
+                span,
+                hir::TyKind::Path(hir::QPath::LangItem(lang_item, self.lower_span(span), None)),
+            )),
+            self.arena.alloc(hir::PathSegment::new(
+                Ident::new(name, span),
+                self.next_id(),
+                Res::Err,
+            )),
+        ));
+        self.expr(span, path)
+    }
+
     pub(super) fn expr_ident(
         &mut self,
         sp: Span,
@@ -1872,12 +1931,25 @@ pub(super) fn expr_block(&mut self, b: &'hir hir::Block<'hir>) -> hir::Expr<'hir
         self.expr(b.span, hir::ExprKind::Block(b, None))
     }
 
+    pub(super) fn expr_array_ref(
+        &mut self,
+        span: Span,
+        elements: &'hir [hir::Expr<'hir>],
+    ) -> hir::Expr<'hir> {
+        let addrof = hir::ExprKind::AddrOf(
+            hir::BorrowKind::Ref,
+            hir::Mutability::Not,
+            self.arena.alloc(self.expr(span, hir::ExprKind::Array(elements))),
+        );
+        self.expr(span, addrof)
+    }
+
     pub(super) fn expr(&mut self, span: Span, kind: hir::ExprKind<'hir>) -> hir::Expr<'hir> {
         let hir_id = self.next_id();
         hir::Expr { hir_id, kind, span: self.lower_span(span) }
     }
 
-    fn expr_field(
+    pub(super) fn expr_field(
         &mut self,
         ident: Ident,
         expr: &'hir hir::Expr<'hir>,
@@ -1892,7 +1964,11 @@ fn expr_field(
         }
     }
 
-    fn arm(&mut self, pat: &'hir hir::Pat<'hir>, expr: &'hir hir::Expr<'hir>) -> hir::Arm<'hir> {
+    pub(super) fn arm(
+        &mut self,
+        pat: &'hir hir::Pat<'hir>,
+        expr: &'hir hir::Expr<'hir>,
+    ) -> hir::Arm<'hir> {
         hir::Arm {
             hir_id: self.next_id(),
             pat,
diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs
new file mode 100644 (file)
index 0000000..e7dd0b1
--- /dev/null
@@ -0,0 +1,398 @@
+use super::LoweringContext;
+use rustc_ast as ast;
+use rustc_ast::visit::{self, Visitor};
+use rustc_ast::*;
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_hir as hir;
+use rustc_span::{
+    sym,
+    symbol::{kw, Ident},
+    Span,
+};
+
+impl<'hir> LoweringContext<'_, 'hir> {
+    pub(crate) fn lower_format_args(&mut self, sp: Span, fmt: &FormatArgs) -> hir::ExprKind<'hir> {
+        expand_format_args(self, sp, fmt)
+    }
+}
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+enum ArgumentType {
+    Format(FormatTrait),
+    Usize,
+}
+
+/// Generate a hir expression representing an argument to a format_args invocation.
+///
+/// Generates:
+///
+/// ```text
+///     <core::fmt::ArgumentV1>::new_…(arg)
+/// ```
+fn make_argument<'hir>(
+    ctx: &mut LoweringContext<'_, 'hir>,
+    sp: Span,
+    arg: &'hir hir::Expr<'hir>,
+    ty: ArgumentType,
+) -> hir::Expr<'hir> {
+    use ArgumentType::*;
+    use FormatTrait::*;
+    let new_fn = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
+        sp,
+        hir::LangItem::FormatArgument,
+        match ty {
+            Format(Display) => sym::new_display,
+            Format(Debug) => sym::new_debug,
+            Format(LowerExp) => sym::new_lower_exp,
+            Format(UpperExp) => sym::new_upper_exp,
+            Format(Octal) => sym::new_octal,
+            Format(Pointer) => sym::new_pointer,
+            Format(Binary) => sym::new_binary,
+            Format(LowerHex) => sym::new_lower_hex,
+            Format(UpperHex) => sym::new_upper_hex,
+            Usize => sym::from_usize,
+        },
+    ));
+    ctx.expr_call_mut(sp, new_fn, std::slice::from_ref(arg))
+}
+
+/// Generate a hir expression for a format_args Count.
+///
+/// Generates:
+///
+/// ```text
+///     <core::fmt::rt::v1::Count>::Is(…)
+/// ```
+///
+/// or
+///
+/// ```text
+///     <core::fmt::rt::v1::Count>::Param(…)
+/// ```
+///
+/// or
+///
+/// ```text
+///     <core::fmt::rt::v1::Count>::Implied
+/// ```
+fn make_count<'hir>(
+    ctx: &mut LoweringContext<'_, 'hir>,
+    sp: Span,
+    count: &Option<FormatCount>,
+    argmap: &mut FxIndexSet<(usize, ArgumentType)>,
+) -> hir::Expr<'hir> {
+    match count {
+        Some(FormatCount::Literal(n)) => {
+            let count_is = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
+                sp,
+                hir::LangItem::FormatCount,
+                sym::Is,
+            ));
+            let value = ctx.arena.alloc_from_iter([ctx.expr_usize(sp, *n)]);
+            ctx.expr_call_mut(sp, count_is, value)
+        }
+        Some(FormatCount::Argument(arg)) => {
+            if let Ok(arg_index) = arg.index {
+                let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize));
+                let count_param = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
+                    sp,
+                    hir::LangItem::FormatCount,
+                    sym::Param,
+                ));
+                let value = ctx.arena.alloc_from_iter([ctx.expr_usize(sp, i)]);
+                ctx.expr_call_mut(sp, count_param, value)
+            } else {
+                ctx.expr(sp, hir::ExprKind::Err)
+            }
+        }
+        None => ctx.expr_lang_item_type_relative(sp, hir::LangItem::FormatCount, sym::Implied),
+    }
+}
+
+/// Generate a hir expression for a format_args placeholder specification.
+///
+/// Generates
+///
+/// ```text
+///     <core::fmt::rt::v1::Argument::new(
+///         …usize, // position
+///         '…', // fill
+///         <core::fmt::rt::v1::Alignment>::…, // alignment
+///         …u32, // flags
+///         <core::fmt::rt::v1::Count::…>, // width
+///         <core::fmt::rt::v1::Count::…>, // precision
+///     )
+/// ```
+fn make_format_spec<'hir>(
+    ctx: &mut LoweringContext<'_, 'hir>,
+    sp: Span,
+    placeholder: &FormatPlaceholder,
+    argmap: &mut FxIndexSet<(usize, ArgumentType)>,
+) -> hir::Expr<'hir> {
+    let position = match placeholder.argument.index {
+        Ok(arg_index) => {
+            let (i, _) =
+                argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait)));
+            ctx.expr_usize(sp, i)
+        }
+        Err(_) => ctx.expr(sp, hir::ExprKind::Err),
+    };
+    let &FormatOptions {
+        ref width,
+        ref precision,
+        alignment,
+        fill,
+        sign,
+        alternate,
+        zero_pad,
+        debug_hex,
+    } = &placeholder.format_options;
+    let fill = ctx.expr_char(sp, fill.unwrap_or(' '));
+    let align = ctx.expr_lang_item_type_relative(
+        sp,
+        hir::LangItem::FormatAlignment,
+        match alignment {
+            Some(FormatAlignment::Left) => sym::Left,
+            Some(FormatAlignment::Right) => sym::Right,
+            Some(FormatAlignment::Center) => sym::Center,
+            None => sym::Unknown,
+        },
+    );
+    // This needs to match `FlagV1` in library/core/src/fmt/mod.rs.
+    let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32)
+        | ((sign == Some(FormatSign::Minus)) as u32) << 1
+        | (alternate as u32) << 2
+        | (zero_pad as u32) << 3
+        | ((debug_hex == Some(FormatDebugHex::Lower)) as u32) << 4
+        | ((debug_hex == Some(FormatDebugHex::Upper)) as u32) << 5;
+    let flags = ctx.expr_u32(sp, flags);
+    let precision = make_count(ctx, sp, &precision, argmap);
+    let width = make_count(ctx, sp, &width, argmap);
+    let format_placeholder_new = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
+        sp,
+        hir::LangItem::FormatPlaceholder,
+        sym::new,
+    ));
+    let args = ctx.arena.alloc_from_iter([position, fill, align, flags, precision, width]);
+    ctx.expr_call_mut(sp, format_placeholder_new, args)
+}
+
+fn expand_format_args<'hir>(
+    ctx: &mut LoweringContext<'_, 'hir>,
+    macsp: Span,
+    fmt: &FormatArgs,
+) -> hir::ExprKind<'hir> {
+    let lit_pieces =
+        ctx.arena.alloc_from_iter(fmt.template.iter().enumerate().filter_map(|(i, piece)| {
+            match piece {
+                &FormatArgsPiece::Literal(s) => Some(ctx.expr_str(fmt.span, s)),
+                &FormatArgsPiece::Placeholder(_) => {
+                    // Inject empty string before placeholders when not already preceded by a literal piece.
+                    if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) {
+                        Some(ctx.expr_str(fmt.span, kw::Empty))
+                    } else {
+                        None
+                    }
+                }
+            }
+        }));
+    let lit_pieces = ctx.expr_array_ref(fmt.span, lit_pieces);
+
+    // Whether we'll use the `Arguments::new_v1_formatted` form (true),
+    // or the `Arguments::new_v1` form (false).
+    let mut use_format_options = false;
+
+    // Create a list of all _unique_ (argument, format trait) combinations.
+    // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
+    let mut argmap = FxIndexSet::default();
+    for piece in &fmt.template {
+        let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
+        if placeholder.format_options != Default::default() {
+            // Can't use basic form if there's any formatting options.
+            use_format_options = true;
+        }
+        if let Ok(index) = placeholder.argument.index {
+            if !argmap.insert((index, ArgumentType::Format(placeholder.format_trait))) {
+                // Duplicate (argument, format trait) combination,
+                // which we'll only put once in the args array.
+                use_format_options = true;
+            }
+        }
+    }
+
+    let format_options = use_format_options.then(|| {
+        // Generate:
+        //     &[format_spec_0, format_spec_1, format_spec_2]
+        let elements: Vec<_> = fmt
+            .template
+            .iter()
+            .filter_map(|piece| {
+                let FormatArgsPiece::Placeholder(placeholder) = piece else { return None };
+                Some(make_format_spec(ctx, macsp, placeholder, &mut argmap))
+            })
+            .collect();
+        ctx.expr_array_ref(macsp, ctx.arena.alloc_from_iter(elements))
+    });
+
+    let arguments = fmt.arguments.all_args();
+
+    // If the args array contains exactly all the original arguments once,
+    // in order, we can use a simple array instead of a `match` construction.
+    // However, if there's a yield point in any argument except the first one,
+    // we don't do this, because an ArgumentV1 cannot be kept across yield points.
+    //
+    // This is an optimization, speeding up compilation about 1-2% in some cases.
+    // See https://github.com/rust-lang/rust/pull/106770#issuecomment-1380790609
+    let use_simple_array = argmap.len() == arguments.len()
+        && argmap.iter().enumerate().all(|(i, &(j, _))| i == j)
+        && arguments.iter().skip(1).all(|arg| !may_contain_yield_point(&arg.expr));
+
+    let args = if use_simple_array {
+        // Generate:
+        //     &[
+        //         <core::fmt::ArgumentV1>::new_display(&arg0),
+        //         <core::fmt::ArgumentV1>::new_lower_hex(&arg1),
+        //         <core::fmt::ArgumentV1>::new_debug(&arg2),
+        //         …
+        //     ]
+        let elements: Vec<_> = arguments
+            .iter()
+            .zip(argmap)
+            .map(|(arg, (_, ty))| {
+                let sp = arg.expr.span.with_ctxt(macsp.ctxt());
+                let arg = ctx.lower_expr(&arg.expr);
+                let ref_arg = ctx.arena.alloc(ctx.expr(
+                    sp,
+                    hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg),
+                ));
+                make_argument(ctx, sp, ref_arg, ty)
+            })
+            .collect();
+        ctx.expr_array_ref(macsp, ctx.arena.alloc_from_iter(elements))
+    } else {
+        // Generate:
+        //     &match (&arg0, &arg1, &…) {
+        //         args => [
+        //             <core::fmt::ArgumentV1>::new_display(args.0),
+        //             <core::fmt::ArgumentV1>::new_lower_hex(args.1),
+        //             <core::fmt::ArgumentV1>::new_debug(args.0),
+        //             …
+        //         ]
+        //     }
+        let args_ident = Ident::new(sym::args, macsp);
+        let (args_pat, args_hir_id) = ctx.pat_ident(macsp, args_ident);
+        let args = ctx.arena.alloc_from_iter(argmap.iter().map(|&(arg_index, ty)| {
+            if let Some(arg) = arguments.get(arg_index) {
+                let sp = arg.expr.span.with_ctxt(macsp.ctxt());
+                let args_ident_expr = ctx.expr_ident(macsp, args_ident, args_hir_id);
+                let arg = ctx.arena.alloc(ctx.expr(
+                    sp,
+                    hir::ExprKind::Field(
+                        args_ident_expr,
+                        Ident::new(sym::integer(arg_index), macsp),
+                    ),
+                ));
+                make_argument(ctx, sp, arg, ty)
+            } else {
+                ctx.expr(macsp, hir::ExprKind::Err)
+            }
+        }));
+        let elements: Vec<_> = arguments
+            .iter()
+            .map(|arg| {
+                let arg_expr = ctx.lower_expr(&arg.expr);
+                ctx.expr(
+                    arg.expr.span.with_ctxt(macsp.ctxt()),
+                    hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, arg_expr),
+                )
+            })
+            .collect();
+        let args_tuple = ctx
+            .arena
+            .alloc(ctx.expr(macsp, hir::ExprKind::Tup(ctx.arena.alloc_from_iter(elements))));
+        let array = ctx.arena.alloc(ctx.expr(macsp, hir::ExprKind::Array(args)));
+        let match_arms = ctx.arena.alloc_from_iter([ctx.arm(args_pat, array)]);
+        let match_expr = ctx.arena.alloc(ctx.expr_match(
+            macsp,
+            args_tuple,
+            match_arms,
+            hir::MatchSource::FormatArgs,
+        ));
+        ctx.expr(
+            macsp,
+            hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, match_expr),
+        )
+    };
+
+    if let Some(format_options) = format_options {
+        // Generate:
+        //     <core::fmt::Arguments>::new_v1_formatted(
+        //         lit_pieces,
+        //         args,
+        //         format_options,
+        //         unsafe { ::core::fmt::UnsafeArg::new() }
+        //     )
+        let new_v1_formatted = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
+            macsp,
+            hir::LangItem::FormatArguments,
+            sym::new_v1_formatted,
+        ));
+        let unsafe_arg_new = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
+            macsp,
+            hir::LangItem::FormatUnsafeArg,
+            sym::new,
+        ));
+        let unsafe_arg_new_call = ctx.expr_call(macsp, unsafe_arg_new, &[]);
+        let hir_id = ctx.next_id();
+        let unsafe_arg = ctx.expr_block(ctx.arena.alloc(hir::Block {
+            stmts: &[],
+            expr: Some(unsafe_arg_new_call),
+            hir_id,
+            rules: hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::CompilerGenerated),
+            span: macsp,
+            targeted_by_break: false,
+        }));
+        let args = ctx.arena.alloc_from_iter([lit_pieces, args, format_options, unsafe_arg]);
+        hir::ExprKind::Call(new_v1_formatted, args)
+    } else {
+        // Generate:
+        //     <core::fmt::Arguments>::new_v1(
+        //         lit_pieces,
+        //         args,
+        //     )
+        let new_v1 = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
+            macsp,
+            hir::LangItem::FormatArguments,
+            sym::new_v1,
+        ));
+        let new_args = ctx.arena.alloc_from_iter([lit_pieces, args]);
+        hir::ExprKind::Call(new_v1, new_args)
+    }
+}
+
+fn may_contain_yield_point(e: &ast::Expr) -> bool {
+    struct MayContainYieldPoint(bool);
+
+    impl Visitor<'_> for MayContainYieldPoint {
+        fn visit_expr(&mut self, e: &ast::Expr) {
+            if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind {
+                self.0 = true;
+            } else {
+                visit::walk_expr(self, e);
+            }
+        }
+
+        fn visit_mac_call(&mut self, _: &ast::MacCall) {
+            // Macros should be expanded at this point.
+            unreachable!("unexpanded macro in ast lowering");
+        }
+
+        fn visit_item(&mut self, _: &ast::Item) {
+            // Do not recurse into nested items.
+        }
+    }
+
+    let mut visitor = MayContainYieldPoint(false);
+    visitor.visit_expr(e);
+    visitor.0
+}
index bc6d2cf12c78aaaeb80e5a50aa936f64cf49d8dd..35849a6b944e481591f8a451646bba6dfd7c0afe 100644 (file)
@@ -80,6 +80,7 @@ macro_rules! arena_vec {
 mod block;
 mod errors;
 mod expr;
+mod format;
 mod index;
 mod item;
 mod lifetime_collector;
@@ -416,6 +417,7 @@ fn compute_hir_hash(
 
 pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
     let sess = tcx.sess;
+    tcx.ensure().output_filenames(());
     let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal();
 
     let ast_index = index_crate(&resolver.node_id_to_def_id, &krate);
index a3e3e823b08eb5b677cafe36e84e8bbe2009cf42..b4900dc39a8af4d98913c75f26146923df617714 100644 (file)
@@ -6,5 +6,6 @@ edition = "2021"
 [lib]
 
 [dependencies]
-rustc_span = { path = "../rustc_span" }
 rustc_ast = { path = "../rustc_ast" }
+rustc_parse_format = { path = "../rustc_parse_format" }
+rustc_span = { path = "../rustc_span" }
index 2a18e5164a309bbb360ccae43d46565b4e83f9ff..cacfe9eb2f10745f8add02cecd528b90ab3a5b0c 100644 (file)
@@ -6,6 +6,11 @@
 use rustc_ast::util::literal::escape_byte_str_symbol;
 use rustc_ast::util::parser::{self, AssocOp, Fixity};
 use rustc_ast::{self as ast, BlockCheckMode};
+use rustc_ast::{
+    FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount, FormatDebugHex, FormatSign,
+    FormatTrait,
+};
+use std::fmt::Write;
 
 impl<'a> State<'a> {
     fn print_else(&mut self, els: Option<&ast::Expr>) {
@@ -527,9 +532,23 @@ pub(super) fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline
                 }
             }
             ast::ExprKind::InlineAsm(a) => {
+                // FIXME: This should have its own syntax, distinct from a macro invocation.
                 self.word("asm!");
                 self.print_inline_asm(a);
             }
+            ast::ExprKind::FormatArgs(fmt) => {
+                // FIXME: This should have its own syntax, distinct from a macro invocation.
+                self.word("format_args!");
+                self.popen();
+                self.rbox(0, Inconsistent);
+                self.word(reconstruct_format_args_template_string(&fmt.template));
+                for arg in fmt.arguments.all_args() {
+                    self.word_space(",");
+                    self.print_expr(&arg.expr);
+                }
+                self.end();
+                self.pclose();
+            }
             ast::ExprKind::MacCall(m) => self.print_mac(m),
             ast::ExprKind::Paren(e) => {
                 self.popen();
@@ -629,3 +648,88 @@ fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) {
         }
     }
 }
+
+pub fn reconstruct_format_args_template_string(pieces: &[FormatArgsPiece]) -> String {
+    let mut template = "\"".to_string();
+    for piece in pieces {
+        match piece {
+            FormatArgsPiece::Literal(s) => {
+                for c in s.as_str().escape_debug() {
+                    template.push(c);
+                    if let '{' | '}' = c {
+                        template.push(c);
+                    }
+                }
+            }
+            FormatArgsPiece::Placeholder(p) => {
+                template.push('{');
+                let (Ok(n) | Err(n)) = p.argument.index;
+                write!(template, "{n}").unwrap();
+                if p.format_options != Default::default() || p.format_trait != FormatTrait::Display
+                {
+                    template.push_str(":");
+                }
+                if let Some(fill) = p.format_options.fill {
+                    template.push(fill);
+                }
+                match p.format_options.alignment {
+                    Some(FormatAlignment::Left) => template.push_str("<"),
+                    Some(FormatAlignment::Right) => template.push_str(">"),
+                    Some(FormatAlignment::Center) => template.push_str("^"),
+                    None => {}
+                }
+                match p.format_options.sign {
+                    Some(FormatSign::Plus) => template.push('+'),
+                    Some(FormatSign::Minus) => template.push('-'),
+                    None => {}
+                }
+                if p.format_options.alternate {
+                    template.push('#');
+                }
+                if p.format_options.zero_pad {
+                    template.push('0');
+                }
+                if let Some(width) = &p.format_options.width {
+                    match width {
+                        FormatCount::Literal(n) => write!(template, "{n}").unwrap(),
+                        FormatCount::Argument(FormatArgPosition {
+                            index: Ok(n) | Err(n), ..
+                        }) => {
+                            write!(template, "{n}$").unwrap();
+                        }
+                    }
+                }
+                if let Some(precision) = &p.format_options.precision {
+                    template.push('.');
+                    match precision {
+                        FormatCount::Literal(n) => write!(template, "{n}").unwrap(),
+                        FormatCount::Argument(FormatArgPosition {
+                            index: Ok(n) | Err(n), ..
+                        }) => {
+                            write!(template, "{n}$").unwrap();
+                        }
+                    }
+                }
+                match p.format_options.debug_hex {
+                    Some(FormatDebugHex::Lower) => template.push('x'),
+                    Some(FormatDebugHex::Upper) => template.push('X'),
+                    None => {}
+                }
+                template.push_str(match p.format_trait {
+                    FormatTrait::Display => "",
+                    FormatTrait::Debug => "?",
+                    FormatTrait::LowerExp => "e",
+                    FormatTrait::UpperExp => "E",
+                    FormatTrait::Octal => "o",
+                    FormatTrait::Pointer => "p",
+                    FormatTrait::Binary => "b",
+                    FormatTrait::LowerHex => "x",
+                    FormatTrait::UpperHex => "X",
+                });
+                template.push('}');
+            }
+        }
+    }
+    template.push('"');
+    template
+}
index ef6de8b109136ca8d156fe615411382fc4a6f82b..e0e814cfc0ac812e94655a920a909da4809555bb 100644 (file)
@@ -367,18 +367,6 @@ fn check_opaque_type_parameter_valid(
     for (i, arg) in opaque_type_key.substs.iter().enumerate() {
         let arg_is_param = match arg.unpack() {
             GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
-            GenericArgKind::Lifetime(lt) if lt.is_static() => {
-                tcx.sess
-                    .struct_span_err(span, "non-defining opaque type use in defining scope")
-                    .span_label(
-                        tcx.def_span(opaque_generics.param_at(i, tcx).def_id),
-                        "cannot use static lifetime; use a bound lifetime \
-                                    instead or remove the lifetime parameter from the \
-                                    opaque type",
-                    )
-                    .emit();
-                return false;
-            }
             GenericArgKind::Lifetime(lt) => {
                 matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
             }
index 93b07801e035d7de24d995980ccd1568063ffb29..342b1735661df9acd779fdf54fc6f7fc6154174c 100644 (file)
@@ -297,6 +297,7 @@ fn manage_cond_expr(&mut self, expr: &mut P<Expr>) {
             | ExprKind::Continue(_)
             | ExprKind::Err
             | ExprKind::Field(_, _)
+            | ExprKind::FormatArgs(_)
             | ExprKind::ForLoop(_, _, _, _)
             | ExprKind::If(_, _, _)
             | ExprKind::IncludedBytes(..)
index 9f4bbbc62c819e516273c409c89eeec3fc72877a..e93a23394c03ff9b9f74ea87e72c6d1ef27ee539 100644 (file)
@@ -1,7 +1,11 @@
 use rustc_ast::ptr::P;
 use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
-use rustc_ast::Expr;
+use rustc_ast::{
+    Expr, ExprKind, FormatAlignment, FormatArgPosition, FormatArgPositionKind, FormatArgs,
+    FormatArgsPiece, FormatArgument, FormatArgumentKind, FormatArguments, FormatCount,
+    FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait,
+};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{pluralize, Applicability, MultiSpan, PResult};
 use rustc_expand::base::{self, *};
 use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
 use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId};
 
-mod ast;
-use ast::*;
-
-mod expand;
-use expand::expand_parsed_format_args;
-
 // The format_args!() macro is expanded in three steps:
 //  1. First, `parse_args` will parse the `(literal, arg, arg, name=arg, name=arg)` syntax,
 //     but doesn't parse the template (the literal) itself.
 //  2. Second, `make_format_args` will parse the template, the format options, resolve argument references,
-//     produce diagnostics, and turn the whole thing into a `FormatArgs` structure.
-//  3. Finally, `expand_parsed_format_args` will turn that `FormatArgs` structure
-//     into the expression that the macro expands to.
+//     produce diagnostics, and turn the whole thing into a `FormatArgs` AST node.
+//  3. Much later, in AST lowering (rustc_ast_lowering), that `FormatArgs` structure will be turned
+//     into the expression of type `core::fmt::Arguments`.
 
-// See format/ast.rs for the FormatArgs structure and glossary.
+// See rustc_ast/src/format.rs for the FormatArgs structure and glossary.
 
 // Only used in parse_args and report_invalid_references,
 // to indicate how a referred argument was used.
@@ -437,7 +435,16 @@ enum ArgRef<'a> {
                     format_options: FormatOptions {
                         fill: format.fill,
                         alignment,
-                        flags: format.flags,
+                        sign: format.sign.map(|s| match s {
+                            parse::Sign::Plus => FormatSign::Plus,
+                            parse::Sign::Minus => FormatSign::Minus,
+                        }),
+                        alternate: format.alternate,
+                        zero_pad: format.zero_pad,
+                        debug_hex: format.debug_hex.map(|s| match s {
+                            parse::DebugHex::Lower => FormatDebugHex::Lower,
+                            parse::DebugHex::Upper => FormatDebugHex::Upper,
+                        }),
                         precision,
                         width,
                     },
@@ -850,7 +857,7 @@ fn expand_format_args_impl<'cx>(
     match parse_args(ecx, sp, tts) {
         Ok((efmt, args)) => {
             if let Ok(format_args) = make_format_args(ecx, efmt, args, nl) {
-                MacEager::expr(expand_parsed_format_args(ecx, format_args))
+                MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args))))
             } else {
                 MacEager::expr(DummyResult::raw_expr(sp, true))
             }
diff --git a/compiler/rustc_builtin_macros/src/format/ast.rs b/compiler/rustc_builtin_macros/src/format/ast.rs
deleted file mode 100644 (file)
index 01dbffa..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-use rustc_ast::ptr::P;
-use rustc_ast::Expr;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_span::symbol::{Ident, Symbol};
-use rustc_span::Span;
-
-// Definitions:
-//
-// format_args!("hello {abc:.xyz$}!!", abc="world");
-// └──────────────────────────────────────────────┘
-//                     FormatArgs
-//
-// format_args!("hello {abc:.xyz$}!!", abc="world");
-//                                     └─────────┘
-//                                      argument
-//
-// format_args!("hello {abc:.xyz$}!!", abc="world");
-//              └───────────────────┘
-//                     template
-//
-// format_args!("hello {abc:.xyz$}!!", abc="world");
-//               └────┘└─────────┘└┘
-//                      pieces
-//
-// format_args!("hello {abc:.xyz$}!!", abc="world");
-//               └────┘           └┘
-//                   literal pieces
-//
-// format_args!("hello {abc:.xyz$}!!", abc="world");
-//                     └─────────┘
-//                     placeholder
-//
-// format_args!("hello {abc:.xyz$}!!", abc="world");
-//                      └─┘  └─┘
-//                      positions (could be names, numbers, empty, or `*`)
-
-/// (Parsed) format args.
-///
-/// Basically the "AST" for a complete `format_args!()`.
-///
-/// E.g., `format_args!("hello {name}");`.
-#[derive(Clone, Debug)]
-pub struct FormatArgs {
-    pub span: Span,
-    pub template: Vec<FormatArgsPiece>,
-    pub arguments: FormatArguments,
-}
-
-/// A piece of a format template string.
-///
-/// E.g. "hello" or "{name}".
-#[derive(Clone, Debug)]
-pub enum FormatArgsPiece {
-    Literal(Symbol),
-    Placeholder(FormatPlaceholder),
-}
-
-/// The arguments to format_args!().
-///
-/// E.g. `1, 2, name="ferris", n=3`,
-/// but also implicit captured arguments like `x` in `format_args!("{x}")`.
-#[derive(Clone, Debug)]
-pub struct FormatArguments {
-    arguments: Vec<FormatArgument>,
-    num_unnamed_args: usize,
-    num_explicit_args: usize,
-    names: FxHashMap<Symbol, usize>,
-}
-
-impl FormatArguments {
-    pub fn new() -> Self {
-        Self {
-            arguments: Vec::new(),
-            names: FxHashMap::default(),
-            num_unnamed_args: 0,
-            num_explicit_args: 0,
-        }
-    }
-
-    pub fn add(&mut self, arg: FormatArgument) -> usize {
-        let index = self.arguments.len();
-        if let Some(name) = arg.kind.ident() {
-            self.names.insert(name.name, index);
-        } else if self.names.is_empty() {
-            // Only count the unnamed args before the first named arg.
-            // (Any later ones are errors.)
-            self.num_unnamed_args += 1;
-        }
-        if !matches!(arg.kind, FormatArgumentKind::Captured(..)) {
-            // This is an explicit argument.
-            // Make sure that all arguments so far are explcit.
-            assert_eq!(
-                self.num_explicit_args,
-                self.arguments.len(),
-                "captured arguments must be added last"
-            );
-            self.num_explicit_args += 1;
-        }
-        self.arguments.push(arg);
-        index
-    }
-
-    pub fn by_name(&self, name: Symbol) -> Option<(usize, &FormatArgument)> {
-        let i = *self.names.get(&name)?;
-        Some((i, &self.arguments[i]))
-    }
-
-    pub fn by_index(&self, i: usize) -> Option<&FormatArgument> {
-        (i < self.num_explicit_args).then(|| &self.arguments[i])
-    }
-
-    pub fn unnamed_args(&self) -> &[FormatArgument] {
-        &self.arguments[..self.num_unnamed_args]
-    }
-
-    pub fn named_args(&self) -> &[FormatArgument] {
-        &self.arguments[self.num_unnamed_args..self.num_explicit_args]
-    }
-
-    pub fn explicit_args(&self) -> &[FormatArgument] {
-        &self.arguments[..self.num_explicit_args]
-    }
-
-    pub fn into_vec(self) -> Vec<FormatArgument> {
-        self.arguments
-    }
-}
-
-#[derive(Clone, Debug)]
-pub struct FormatArgument {
-    pub kind: FormatArgumentKind,
-    pub expr: P<Expr>,
-}
-
-#[derive(Clone, Debug)]
-pub enum FormatArgumentKind {
-    /// `format_args(…, arg)`
-    Normal,
-    /// `format_args(…, arg = 1)`
-    Named(Ident),
-    /// `format_args("… {arg} …")`
-    Captured(Ident),
-}
-
-impl FormatArgumentKind {
-    pub fn ident(&self) -> Option<Ident> {
-        match self {
-            &Self::Normal => None,
-            &Self::Named(id) => Some(id),
-            &Self::Captured(id) => Some(id),
-        }
-    }
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct FormatPlaceholder {
-    /// Index into [`FormatArgs::arguments`].
-    pub argument: FormatArgPosition,
-    /// The span inside the format string for the full `{…}` placeholder.
-    pub span: Option<Span>,
-    /// `{}`, `{:?}`, or `{:x}`, etc.
-    pub format_trait: FormatTrait,
-    /// `{}` or `{:.5}` or `{:-^20}`, etc.
-    pub format_options: FormatOptions,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct FormatArgPosition {
-    /// Which argument this position refers to (Ok),
-    /// or would've referred to if it existed (Err).
-    pub index: Result<usize, usize>,
-    /// What kind of position this is. See [`FormatArgPositionKind`].
-    pub kind: FormatArgPositionKind,
-    /// The span of the name or number.
-    pub span: Option<Span>,
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum FormatArgPositionKind {
-    /// `{}` or `{:.*}`
-    Implicit,
-    /// `{1}` or `{:1$}` or `{:.1$}`
-    Number,
-    /// `{a}` or `{:a$}` or `{:.a$}`
-    Named,
-}
-
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub enum FormatTrait {
-    /// `{}`
-    Display,
-    /// `{:?}`
-    Debug,
-    /// `{:e}`
-    LowerExp,
-    /// `{:E}`
-    UpperExp,
-    /// `{:o}`
-    Octal,
-    /// `{:p}`
-    Pointer,
-    /// `{:b}`
-    Binary,
-    /// `{:x}`
-    LowerHex,
-    /// `{:X}`
-    UpperHex,
-}
-
-#[derive(Clone, Debug, Default, PartialEq, Eq)]
-pub struct FormatOptions {
-    /// The width. E.g. `{:5}` or `{:width$}`.
-    pub width: Option<FormatCount>,
-    /// The precision. E.g. `{:.5}` or `{:.precision$}`.
-    pub precision: Option<FormatCount>,
-    /// The alignment. E.g. `{:>}` or `{:<}` or `{:^}`.
-    pub alignment: Option<FormatAlignment>,
-    /// The fill character. E.g. the `.` in `{:.>10}`.
-    pub fill: Option<char>,
-    /// The `+`, `-`, `0`, `#`, `x?` and `X?` flags.
-    pub flags: u32,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum FormatAlignment {
-    /// `{:<}`
-    Left,
-    /// `{:>}`
-    Right,
-    /// `{:^}`
-    Center,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum FormatCount {
-    /// `{:5}` or `{:.5}`
-    Literal(usize),
-    /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc.
-    Argument(FormatArgPosition),
-}
diff --git a/compiler/rustc_builtin_macros/src/format/expand.rs b/compiler/rustc_builtin_macros/src/format/expand.rs
deleted file mode 100644 (file)
index 9dde5ef..0000000
+++ /dev/null
@@ -1,353 +0,0 @@
-use super::*;
-use rustc_ast as ast;
-use rustc_ast::visit::{self, Visitor};
-use rustc_ast::{BlockCheckMode, UnsafeSource};
-use rustc_data_structures::fx::FxIndexSet;
-use rustc_span::{sym, symbol::kw};
-
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-enum ArgumentType {
-    Format(FormatTrait),
-    Usize,
-}
-
-fn make_argument(ecx: &ExtCtxt<'_>, sp: Span, arg: P<ast::Expr>, ty: ArgumentType) -> P<ast::Expr> {
-    // Generate:
-    //     ::core::fmt::ArgumentV1::new_…(arg)
-    use ArgumentType::*;
-    use FormatTrait::*;
-    ecx.expr_call_global(
-        sp,
-        ecx.std_path(&[
-            sym::fmt,
-            sym::ArgumentV1,
-            match ty {
-                Format(Display) => sym::new_display,
-                Format(Debug) => sym::new_debug,
-                Format(LowerExp) => sym::new_lower_exp,
-                Format(UpperExp) => sym::new_upper_exp,
-                Format(Octal) => sym::new_octal,
-                Format(Pointer) => sym::new_pointer,
-                Format(Binary) => sym::new_binary,
-                Format(LowerHex) => sym::new_lower_hex,
-                Format(UpperHex) => sym::new_upper_hex,
-                Usize => sym::from_usize,
-            },
-        ]),
-        vec![arg],
-    )
-}
-
-fn make_count(
-    ecx: &ExtCtxt<'_>,
-    sp: Span,
-    count: &Option<FormatCount>,
-    argmap: &mut FxIndexSet<(usize, ArgumentType)>,
-) -> P<ast::Expr> {
-    // Generate:
-    //     ::core::fmt::rt::v1::Count::…(…)
-    match count {
-        Some(FormatCount::Literal(n)) => ecx.expr_call_global(
-            sp,
-            ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Is]),
-            vec![ecx.expr_usize(sp, *n)],
-        ),
-        Some(FormatCount::Argument(arg)) => {
-            if let Ok(arg_index) = arg.index {
-                let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize));
-                ecx.expr_call_global(
-                    sp,
-                    ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Param]),
-                    vec![ecx.expr_usize(sp, i)],
-                )
-            } else {
-                DummyResult::raw_expr(sp, true)
-            }
-        }
-        None => ecx.expr_path(ecx.path_global(
-            sp,
-            ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Count, sym::Implied]),
-        )),
-    }
-}
-
-fn make_format_spec(
-    ecx: &ExtCtxt<'_>,
-    sp: Span,
-    placeholder: &FormatPlaceholder,
-    argmap: &mut FxIndexSet<(usize, ArgumentType)>,
-) -> P<ast::Expr> {
-    // Generate:
-    //     ::core::fmt::rt::v1::Argument {
-    //         position: 0usize,
-    //         format: ::core::fmt::rt::v1::FormatSpec {
-    //             fill: ' ',
-    //             align: ::core::fmt::rt::v1::Alignment::Unknown,
-    //             flags: 0u32,
-    //             precision: ::core::fmt::rt::v1::Count::Implied,
-    //             width: ::core::fmt::rt::v1::Count::Implied,
-    //         },
-    //     }
-    let position = match placeholder.argument.index {
-        Ok(arg_index) => {
-            let (i, _) =
-                argmap.insert_full((arg_index, ArgumentType::Format(placeholder.format_trait)));
-            ecx.expr_usize(sp, i)
-        }
-        Err(_) => DummyResult::raw_expr(sp, true),
-    };
-    let fill = ecx.expr_char(sp, placeholder.format_options.fill.unwrap_or(' '));
-    let align = ecx.expr_path(ecx.path_global(
-        sp,
-        ecx.std_path(&[
-            sym::fmt,
-            sym::rt,
-            sym::v1,
-            sym::Alignment,
-            match placeholder.format_options.alignment {
-                Some(FormatAlignment::Left) => sym::Left,
-                Some(FormatAlignment::Right) => sym::Right,
-                Some(FormatAlignment::Center) => sym::Center,
-                None => sym::Unknown,
-            },
-        ]),
-    ));
-    let flags = ecx.expr_u32(sp, placeholder.format_options.flags);
-    let prec = make_count(ecx, sp, &placeholder.format_options.precision, argmap);
-    let width = make_count(ecx, sp, &placeholder.format_options.width, argmap);
-    ecx.expr_struct(
-        sp,
-        ecx.path_global(sp, ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::Argument])),
-        vec![
-            ecx.field_imm(sp, Ident::new(sym::position, sp), position),
-            ecx.field_imm(
-                sp,
-                Ident::new(sym::format, sp),
-                ecx.expr_struct(
-                    sp,
-                    ecx.path_global(
-                        sp,
-                        ecx.std_path(&[sym::fmt, sym::rt, sym::v1, sym::FormatSpec]),
-                    ),
-                    vec![
-                        ecx.field_imm(sp, Ident::new(sym::fill, sp), fill),
-                        ecx.field_imm(sp, Ident::new(sym::align, sp), align),
-                        ecx.field_imm(sp, Ident::new(sym::flags, sp), flags),
-                        ecx.field_imm(sp, Ident::new(sym::precision, sp), prec),
-                        ecx.field_imm(sp, Ident::new(sym::width, sp), width),
-                    ],
-                ),
-            ),
-        ],
-    )
-}
-
-pub fn expand_parsed_format_args(ecx: &mut ExtCtxt<'_>, fmt: FormatArgs) -> P<ast::Expr> {
-    let macsp = ecx.with_def_site_ctxt(ecx.call_site());
-
-    let lit_pieces = ecx.expr_array_ref(
-        fmt.span,
-        fmt.template
-            .iter()
-            .enumerate()
-            .filter_map(|(i, piece)| match piece {
-                &FormatArgsPiece::Literal(s) => Some(ecx.expr_str(fmt.span, s)),
-                &FormatArgsPiece::Placeholder(_) => {
-                    // Inject empty string before placeholders when not already preceded by a literal piece.
-                    if i == 0 || matches!(fmt.template[i - 1], FormatArgsPiece::Placeholder(_)) {
-                        Some(ecx.expr_str(fmt.span, kw::Empty))
-                    } else {
-                        None
-                    }
-                }
-            })
-            .collect(),
-    );
-
-    // Whether we'll use the `Arguments::new_v1_formatted` form (true),
-    // or the `Arguments::new_v1` form (false).
-    let mut use_format_options = false;
-
-    // Create a list of all _unique_ (argument, format trait) combinations.
-    // E.g. "{0} {0:x} {0} {1}" -> [(0, Display), (0, LowerHex), (1, Display)]
-    let mut argmap = FxIndexSet::default();
-    for piece in &fmt.template {
-        let FormatArgsPiece::Placeholder(placeholder) = piece else { continue };
-        if placeholder.format_options != Default::default() {
-            // Can't use basic form if there's any formatting options.
-            use_format_options = true;
-        }
-        if let Ok(index) = placeholder.argument.index {
-            if !argmap.insert((index, ArgumentType::Format(placeholder.format_trait))) {
-                // Duplicate (argument, format trait) combination,
-                // which we'll only put once in the args array.
-                use_format_options = true;
-            }
-        }
-    }
-
-    let format_options = use_format_options.then(|| {
-        // Generate:
-        //     &[format_spec_0, format_spec_1, format_spec_2]
-        ecx.expr_array_ref(
-            macsp,
-            fmt.template
-                .iter()
-                .filter_map(|piece| {
-                    let FormatArgsPiece::Placeholder(placeholder) = piece else { return None };
-                    Some(make_format_spec(ecx, macsp, placeholder, &mut argmap))
-                })
-                .collect(),
-        )
-    });
-
-    let arguments = fmt.arguments.into_vec();
-
-    // If the args array contains exactly all the original arguments once,
-    // in order, we can use a simple array instead of a `match` construction.
-    // However, if there's a yield point in any argument except the first one,
-    // we don't do this, because an ArgumentV1 cannot be kept across yield points.
-    let use_simple_array = argmap.len() == arguments.len()
-        && argmap.iter().enumerate().all(|(i, &(j, _))| i == j)
-        && arguments.iter().skip(1).all(|arg| !may_contain_yield_point(&arg.expr));
-
-    let args = if use_simple_array {
-        // Generate:
-        //     &[
-        //         ::core::fmt::ArgumentV1::new_display(&arg0),
-        //         ::core::fmt::ArgumentV1::new_lower_hex(&arg1),
-        //         ::core::fmt::ArgumentV1::new_debug(&arg2),
-        //     ]
-        ecx.expr_array_ref(
-            macsp,
-            arguments
-                .into_iter()
-                .zip(argmap)
-                .map(|(arg, (_, ty))| {
-                    let sp = arg.expr.span.with_ctxt(macsp.ctxt());
-                    make_argument(ecx, sp, ecx.expr_addr_of(sp, arg.expr), ty)
-                })
-                .collect(),
-        )
-    } else {
-        // Generate:
-        //     match (&arg0, &arg1, &arg2) {
-        //         args => &[
-        //             ::core::fmt::ArgumentV1::new_display(args.0),
-        //             ::core::fmt::ArgumentV1::new_lower_hex(args.1),
-        //             ::core::fmt::ArgumentV1::new_debug(args.0),
-        //         ]
-        //     }
-        let args_ident = Ident::new(sym::args, macsp);
-        let args = argmap
-            .iter()
-            .map(|&(arg_index, ty)| {
-                if let Some(arg) = arguments.get(arg_index) {
-                    let sp = arg.expr.span.with_ctxt(macsp.ctxt());
-                    make_argument(
-                        ecx,
-                        sp,
-                        ecx.expr_field(
-                            sp,
-                            ecx.expr_ident(macsp, args_ident),
-                            Ident::new(sym::integer(arg_index), macsp),
-                        ),
-                        ty,
-                    )
-                } else {
-                    DummyResult::raw_expr(macsp, true)
-                }
-            })
-            .collect();
-        ecx.expr_addr_of(
-            macsp,
-            ecx.expr_match(
-                macsp,
-                ecx.expr_tuple(
-                    macsp,
-                    arguments
-                        .into_iter()
-                        .map(|arg| {
-                            ecx.expr_addr_of(arg.expr.span.with_ctxt(macsp.ctxt()), arg.expr)
-                        })
-                        .collect(),
-                ),
-                vec![ecx.arm(macsp, ecx.pat_ident(macsp, args_ident), ecx.expr_array(macsp, args))],
-            ),
-        )
-    };
-
-    if let Some(format_options) = format_options {
-        // Generate:
-        //     ::core::fmt::Arguments::new_v1_formatted(
-        //         lit_pieces,
-        //         args,
-        //         format_options,
-        //         unsafe { ::core::fmt::UnsafeArg::new() }
-        //     )
-        ecx.expr_call_global(
-            macsp,
-            ecx.std_path(&[sym::fmt, sym::Arguments, sym::new_v1_formatted]),
-            vec![
-                lit_pieces,
-                args,
-                format_options,
-                ecx.expr_block(P(ast::Block {
-                    stmts: vec![ecx.stmt_expr(ecx.expr_call_global(
-                        macsp,
-                        ecx.std_path(&[sym::fmt, sym::UnsafeArg, sym::new]),
-                        Vec::new(),
-                    ))],
-                    id: ast::DUMMY_NODE_ID,
-                    rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated),
-                    span: macsp,
-                    tokens: None,
-                    could_be_bare_literal: false,
-                })),
-            ],
-        )
-    } else {
-        // Generate:
-        //     ::core::fmt::Arguments::new_v1(
-        //         lit_pieces,
-        //         args,
-        //     )
-        ecx.expr_call_global(
-            macsp,
-            ecx.std_path(&[sym::fmt, sym::Arguments, sym::new_v1]),
-            vec![lit_pieces, args],
-        )
-    }
-}
-
-fn may_contain_yield_point(e: &ast::Expr) -> bool {
-    struct MayContainYieldPoint(bool);
-
-    impl Visitor<'_> for MayContainYieldPoint {
-        fn visit_expr(&mut self, e: &ast::Expr) {
-            if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind {
-                self.0 = true;
-            } else {
-                visit::walk_expr(self, e);
-            }
-        }
-
-        fn visit_mac_call(&mut self, _: &ast::MacCall) {
-            self.0 = true;
-        }
-
-        fn visit_attribute(&mut self, _: &ast::Attribute) {
-            // Conservatively assume this may be a proc macro attribute in
-            // expression position.
-            self.0 = true;
-        }
-
-        fn visit_item(&mut self, _: &ast::Item) {
-            // Do not recurse into nested items.
-        }
-    }
-
-    let mut visitor = MayContainYieldPoint(false);
-    visitor.visit_expr(e);
-    visitor.0
-}
index d627c2ee09c4ef7555f820cc2a239b73c3133269..7886cae42a15ab1902d7d79ce677e8c4dd0be075 100644 (file)
@@ -1,13 +1,11 @@
 task:
   name: freebsd
   freebsd_instance:
-    image: freebsd-12-1-release-amd64
+    image: freebsd-13-1-release-amd64
   setup_rust_script:
     - pkg install -y curl git bash
     - curl https://sh.rustup.rs -sSf --output rustup.sh
     - sh rustup.sh --default-toolchain none -y --profile=minimal
-  cargo_bin_cache:
-    folder: ~/.cargo/bin
   target_cache:
     folder: target
   prepare_script:
@@ -15,9 +13,4 @@ task:
     - ./y.rs prepare
   test_script:
     - . $HOME/.cargo/env
-    - # Enable backtraces for easier debugging
-    - export RUST_BACKTRACE=1
-    - # Reduce amount of benchmark runs as they are slow
-    - export COMPILE_RUNS=2
-    - export RUN_RUNS=2
     - ./y.rs test
index a6bb12a66a247d66441c390105655e9ff0910978..c0daf69e98e912560c68b378f5c36bac6cf3004d 100644 (file)
@@ -25,6 +25,10 @@ jobs:
     runs-on: ${{ matrix.os }}
     timeout-minutes: 60
 
+    defaults:
+      run:
+        shell: bash
+
     strategy:
       fail-fast: false
       matrix:
@@ -46,36 +50,31 @@ jobs:
           - os: ubuntu-latest
             env:
               TARGET_TRIPLE: s390x-unknown-linux-gnu
+          - os: windows-latest
+            env:
+              TARGET_TRIPLE: x86_64-pc-windows-msvc
+          - os: windows-latest
+            env:
+              TARGET_TRIPLE: x86_64-pc-windows-gnu
 
     steps:
     - uses: actions/checkout@v3
 
-    - name: Cache cargo installed crates
-      uses: actions/cache@v3
-      with:
-        path: ~/.cargo/bin
-        key: ${{ runner.os }}-cargo-installed-crates
-
-    - name: Cache cargo registry and index
-      uses: actions/cache@v3
-      with:
-        path: |
-            ~/.cargo/registry
-            ~/.cargo/git
-        key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
-
     - name: Cache cargo target dir
       uses: actions/cache@v3
       with:
         path: build/cg_clif
-        key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
+        key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
+
+    - name: Set MinGW as the default toolchain
+      if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
+      run: rustup set default-host x86_64-pc-windows-gnu
 
     - name: Install MinGW toolchain and wine
       if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
       run: |
         sudo apt-get update
         sudo apt-get install -y gcc-mingw-w64-x86-64 wine-stable
-        rustup target add x86_64-pc-windows-gnu
 
     - name: Install AArch64 toolchain and qemu
       if: matrix.os == 'ubuntu-latest' && matrix.env.TARGET_TRIPLE == 'aarch64-unknown-linux-gnu'
@@ -89,6 +88,13 @@ jobs:
         sudo apt-get update
         sudo apt-get install -y gcc-s390x-linux-gnu qemu-user
 
+    - name: Use sparse cargo registry
+      run: |
+        cat >> ~/.cargo/config.toml <<EOF
+        [unstable]
+        sparse-registry = true
+        EOF
+
     - name: Prepare dependencies
       run: ./y.rs prepare
 
@@ -104,49 +110,47 @@ jobs:
     - name: Test
       env:
         TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }}
-      run: |
-        # Enable backtraces for easier debugging
-        export RUST_BACKTRACE=1
-
-        # Reduce amount of benchmark runs as they are slow
-        export COMPILE_RUNS=2
-        export RUN_RUNS=2
-
-        # Enable extra checks
-        export CG_CLIF_ENABLE_VERIFIER=1
-
-        ./y.rs test
+      run: ./y.rs test
 
     - name: Package prebuilt cg_clif
       run: tar cvfJ cg_clif.tar.xz dist
 
     - name: Upload prebuilt cg_clif
-      if: matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu'
-      uses: actions/upload-artifact@v2
+      if: matrix.os == 'windows-latest' || matrix.env.TARGET_TRIPLE != 'x86_64-pc-windows-gnu'
+      uses: actions/upload-artifact@v3
       with:
         name: cg_clif-${{ matrix.env.TARGET_TRIPLE }}
         path: cg_clif.tar.xz
 
     - name: Upload prebuilt cg_clif (cross compile)
-      if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
+      if: matrix.os != 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
       uses: actions/upload-artifact@v3
       with:
         name: cg_clif-${{ runner.os }}-cross-x86_64-mingw
         path: cg_clif.tar.xz
 
-  windows:
+
+  abi_cafe:
     runs-on: ${{ matrix.os }}
     timeout-minutes: 60
 
+    defaults:
+      run:
+        shell: bash
+
     strategy:
-      fail-fast: false
+      fail-fast: true
       matrix:
         include:
-          # Native Windows build with MSVC
+          - os: ubuntu-latest
+            env:
+              TARGET_TRIPLE: x86_64-unknown-linux-gnu
+          - os: macos-latest
+            env:
+              TARGET_TRIPLE: x86_64-apple-darwin
           - os: windows-latest
             env:
               TARGET_TRIPLE: x86_64-pc-windows-msvc
-          # cross-compile from Windows to Windows MinGW
           - os: windows-latest
             env:
               TARGET_TRIPLE: x86_64-pc-windows-gnu
@@ -154,20 +158,6 @@ jobs:
     steps:
     - uses: actions/checkout@v3
 
-    - name: Cache cargo installed crates
-      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@v3
-      with:
-        path: |
-            ~/.cargo/registry
-            ~/.cargo/git
-        key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
-
     - name: Cache cargo target dir
       uses: actions/cache@v3
       with:
@@ -178,50 +168,20 @@ jobs:
       if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
       run: rustup set default-host x86_64-pc-windows-gnu
 
-    - name: Prepare dependencies
+    - name: Use sparse cargo registry
       run: |
-        git config --global core.autocrlf false
-        rustc y.rs -o y.exe -g
-        ./y.exe prepare
+        cat >> ~/.cargo/config.toml <<EOF
+        [unstable]
+        sparse-registry = true
+        EOF
 
-    - name: Build without unstable features
-      env:
-        TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }}
-      # This is the config rust-lang/rust uses for builds
-      run: ./y.rs build --no-unstable-features
+    - name: Prepare dependencies
+      run: ./y.rs prepare
 
     - name: Build
       run: ./y.rs build --sysroot none
 
-    - name: Test
-      run: |
-        # Enable backtraces for easier debugging
-        $Env:RUST_BACKTRACE=1
-
-        # Reduce amount of benchmark runs as they are slow
-        $Env:COMPILE_RUNS=2
-        $Env:RUN_RUNS=2
-
-        # 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
-        (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 dist
-
-    - name: Upload prebuilt cg_clif
-      uses: actions/upload-artifact@v3
-      with:
-        name: cg_clif-${{ matrix.env.TARGET_TRIPLE }}
-        path: cg_clif.tar
+    - name: Test abi-cafe
+      env:
+        TARGET_TRIPLE: ${{ matrix.env.TARGET_TRIPLE }}
+      run: ./y.rs abi-cafe
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml b/compiler/rustc_codegen_cranelift/.github/workflows/nightly-cranelift.yml
deleted file mode 100644 (file)
index d0d58d2..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-name: Test nightly Cranelift
-
-on:
-  push:
-  schedule:
-    - cron: '17 1 * * *' # At 01:17 UTC every day.
-
-jobs:
-  build:
-    runs-on: ubuntu-latest
-    timeout-minutes: 60
-
-    steps:
-    - uses: actions/checkout@v3
-
-    - name: Cache cargo installed crates
-      uses: actions/cache@v3
-      with:
-        path: ~/.cargo/bin
-        key: ubuntu-latest-cargo-installed-crates
-
-    - name: Prepare dependencies
-      run: |
-        git config --global user.email "user@example.com"
-        git config --global user.name "User"
-        ./y.rs prepare
-
-    - name: Patch Cranelift
-      run: |
-        sed -i 's/cranelift-codegen = { version = "\w*.\w*.\w*", features = \["unwind", "all-arch"\] }/cranelift-codegen = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git", features = ["unwind", "all-arch"] }/' Cargo.toml
-        sed -i 's/cranelift-frontend = "\w*.\w*.\w*"/cranelift-frontend = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml
-        sed -i 's/cranelift-module = "\w*.\w*.\w*"/cranelift-module = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml
-        sed -i 's/cranelift-native = "\w*.\w*.\w*"/cranelift-native = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml
-        sed -i 's/cranelift-jit = { version = "\w*.\w*.\w*", optional = true }/cranelift-jit = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git", optional = true }/' Cargo.toml
-        sed -i 's/cranelift-object = "\w*.\w*.\w*"/cranelift-object = { git = "https:\/\/github.com\/bytecodealliance\/wasmtime.git" }/' Cargo.toml
-
-        sed -i 's/object = { version = "0.27.0"/object = { version = "0.28.0"/' Cargo.toml
-
-        cat Cargo.toml
-
-    - name: Build without unstable features
-      # This is the config rust-lang/rust uses for builds
-      run: ./y.rs build --no-unstable-features
-
-    - name: Build
-      run: ./y.rs build --sysroot none
-    - name: Test
-      run: |
-        # Enable backtraces for easier debugging
-        export RUST_BACKTRACE=1
-
-        # Reduce amount of benchmark runs as they are slow
-        export COMPILE_RUNS=2
-        export RUN_RUNS=2
-
-        # Enable extra checks
-        export CG_CLIF_ENABLE_VERIFIER=1
-
-        ./test.sh
index bef806318efa836aeeb8d6df06d880b77be677fb..5faa8f0540451b848506fadd139fc6333429b230 100644 (file)
@@ -10,73 +10,45 @@ jobs:
     steps:
     - uses: actions/checkout@v3
 
-    - name: Cache cargo installed crates
-      uses: actions/cache@v3
-      with:
-        path: ~/.cargo/bin
-        key: ${{ runner.os }}-cargo-installed-crates
-
-    - name: Cache cargo registry and index
-      uses: actions/cache@v3
-      with:
-        path: |
-            ~/.cargo/registry
-            ~/.cargo/git
-        key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
-
     - name: Cache cargo target dir
       uses: actions/cache@v3
       with:
         path: build/cg_clif
         key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
 
-    - name: Prepare dependencies
+    - name: Use sparse cargo registry
       run: |
-        git config --global user.email "user@example.com"
-        git config --global user.name "User"
-        ./y.rs prepare
+        cat >> ~/.cargo/config.toml <<EOF
+        [unstable]
+        sparse-registry = true
+        EOF
 
-    - name: Test
-      run: |
-        # Enable backtraces for easier debugging
-        export RUST_BACKTRACE=1
+    - name: Prepare dependencies
+      run: ./y.rs prepare
 
-        ./scripts/test_bootstrap.sh
+    - name: Test
+      run: ./scripts/test_bootstrap.sh
   rustc_test_suite:
     runs-on: ubuntu-latest
 
     steps:
     - uses: actions/checkout@v3
 
-    - name: Cache cargo installed crates
-      uses: actions/cache@v3
-      with:
-        path: ~/.cargo/bin
-        key: ${{ runner.os }}-cargo-installed-crates
-
-    - name: Cache cargo registry and index
-      uses: actions/cache@v3
-      with:
-        path: |
-            ~/.cargo/registry
-            ~/.cargo/git
-        key: ${{ runner.os }}-cargo-registry-and-index-${{ hashFiles('**/Cargo.lock') }}
-
     - name: Cache cargo target dir
       uses: actions/cache@v3
       with:
         path: build/cg_clif
         key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
 
-    - name: Prepare dependencies
+    - name: Use sparse cargo registry
       run: |
-        git config --global user.email "user@example.com"
-        git config --global user.name "User"
-        ./y.rs prepare
+        cat >> ~/.cargo/config.toml <<EOF
+        [unstable]
+        sparse-registry = true
+        EOF
 
-    - name: Test
-      run: |
-        # Enable backtraces for easier debugging
-        export RUST_BACKTRACE=1
+    - name: Prepare dependencies
+      run: ./y.rs prepare
 
-        ./scripts/test_rustc_tests.sh
+    - name: Test
+      run: ./scripts/test_rustc_tests.sh
index b443fd58a1b98344bec2720e26139b6467907d89..8012e93f6a90ebdee2747548145a52b8f2e3f45c 100644 (file)
@@ -1,4 +1,4 @@
-target
+/target
 **/*.rs.bk
 *.rlib
 *.o
@@ -11,9 +11,6 @@ perf.data.old
 /y.exe
 /y.pdb
 /build
-/build_sysroot/sysroot_src
-/build_sysroot/compiler-builtins
-/build_sysroot/rustc_version
 /dist
 /rust
 /download
index bc914e37d2b51dda8d3a0e4ef090a4cc1399fc90..7c8703cba505c6e221910aabcef2a5ea4f712a41 100644 (file)
@@ -1,4 +1,6 @@
 {
+    "editor.formatOnSave": true,
+
     // source for rustc_* is not included in the rust-src component; disable the errors about this
     "rust-analyzer.diagnostics.disabled": ["unresolved-extern-crate", "unresolved-macro-call"],
     "rust-analyzer.imports.granularity.enforce": true,
@@ -30,7 +32,7 @@
             ]
         },
         {
-            "sysroot_src": "./build_sysroot/sysroot_src/library",
+            "sysroot_src": "./download/sysroot/sysroot_src/library",
             "crates": [
                 {
                     "root_module": "./example/std_example.rs",
index e4d3e9ca5ae0a8676863063216c420232248a554..50249ea1bdb493e08815b1f81c373c4a1d4937db 100644 (file)
@@ -57,28 +57,28 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.90.1"
+version = "0.92.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b62c772976416112fa4484cbd688cb6fb35fd430005c1c586224fc014018abad"
+checksum = "2f3d54eab028f5805ae3b26fd60eca3f3a9cfb76b989d9bab173be3f61356cc3"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.90.1"
+version = "0.92.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b40ed2dd13c2ac7e24f88a3090c68ad3414eb1d066a95f8f1f7b3b819cb4e46"
+checksum = "2be1d5f2c3cca1efb691844bc1988b89c77291f13f778499a3f3c0cf49c0ed61"
 dependencies = [
  "arrayvec",
  "bumpalo",
  "cranelift-bforest",
  "cranelift-codegen-meta",
  "cranelift-codegen-shared",
- "cranelift-egraph",
  "cranelift-entity",
  "cranelift-isle",
  "gimli",
+ "hashbrown",
  "log",
  "regalloc2",
  "smallvec",
@@ -87,44 +87,30 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.90.1"
+version = "0.92.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb927a8f1c27c34ee3759b6b0ffa528d2330405d5cc4511f0cab33fe2279f4b5"
+checksum = "3f9b1b1089750ce4005893af7ee00bb08a2cf1c9779999c0f7164cbc8ad2e0d2"
 dependencies = [
  "cranelift-codegen-shared",
 ]
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.90.1"
+version = "0.92.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-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",
-]
+checksum = "cc5fbaec51de47297fd7304986fd53c8c0030abbe69728a60d72e1c63559318d"
 
 [[package]]
 name = "cranelift-entity"
-version = "0.90.1"
+version = "0.92.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0637ffde963cb5d759bc4d454cfa364b6509e6c74cdaa21298add0ed9276f346"
+checksum = "dab984c94593f876090fae92e984bdcc74d9b1acf740ab5f79036001c65cba13"
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.90.1"
+version = "0.92.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb72b8342685e850cb037350418f62cc4fc55d6c2eb9c7ca01b82f9f1a6f3d56"
+checksum = "6e0cb3102d21a2fe5f3210af608748ddd0cd09825ac12d42dc56ed5ed8725fe0"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -134,15 +120,15 @@ dependencies = [
 
 [[package]]
 name = "cranelift-isle"
-version = "0.90.1"
+version = "0.92.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "850579cb9e4b448f7c301f1e6e6cbad99abe3f1f1d878a4994cb66e33c6db8cd"
+checksum = "72101dd1f441d629735143c41e00b3428f9267738176983ef588ff43382af0a0"
 
 [[package]]
 name = "cranelift-jit"
-version = "0.90.1"
+version = "0.92.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9add822ad66dcbe152b5ab57de10240a2df4505099f2f6c27159acb711890bd4"
+checksum = "6557f8ce44d498777f2495aa58d9692a4a37d6f84aa445750d666cef770b6a5c"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -159,9 +145,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-module"
-version = "0.90.1"
+version = "0.92.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "406b772626fc2664864cf947f3895a23b619895c7fff635f3622e2d857f4492f"
+checksum = "88807e1c0c47ec02fe433333ccbe56b480425418b1470e333205e11650697d72"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -169,9 +155,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-native"
-version = "0.90.1"
+version = "0.92.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d0a279e5bcba3e0466c734d8d8eb6bfc1ad29e95c37f3e4955b492b5616335e"
+checksum = "c22b0d9fcbe3fc5a1af9e7021b44ce42b930bcefac446ce22e02e8f9a0d67120"
 dependencies = [
  "cranelift-codegen",
  "libc",
@@ -180,9 +166,9 @@ dependencies = [
 
 [[package]]
 name = "cranelift-object"
-version = "0.90.1"
+version = "0.92.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39793c550f0c1d7db96c2fc1324583670c8143befe6edbfbaf1c68aba53be983"
+checksum = "341375758d7c3fedc0b5315f552e6f0feac46baf87c450a15e9455ef47c2b261"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -317,9 +303,9 @@ checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
 
 [[package]]
 name = "regalloc2"
-version = "0.4.2"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91b2eab54204ea0117fe9a060537e0b07a4e72f7c7d182361ecc346cab2240e5"
+checksum = "300d4fbfb40c1c66a78ba3ddd41c1110247cf52f97b87d0f2fc9209bd49b030c"
 dependencies = [
  "fxhash",
  "log",
@@ -347,7 +333,6 @@ dependencies = [
  "cranelift-frontend",
  "cranelift-jit",
  "cranelift-module",
- "cranelift-native",
  "cranelift-object",
  "gimli",
  "indexmap",
@@ -396,9 +381,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasmtime-jit-icache-coherence"
-version = "2.0.1"
+version = "5.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6bbabb309c06cc238ee91b1455b748c45f0bdcab0dda2c2db85b0a1e69fcb66"
+checksum = "08fcba5ebd96da2a9f0747ab6337fe9788adfb3f63fa2c180520d665562d257e"
 dependencies = [
  "cfg-if",
  "libc",
@@ -429,43 +414,57 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "windows-sys"
-version = "0.36.1"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
+checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
 dependencies = [
+ "windows_aarch64_gnullvm",
  "windows_aarch64_msvc",
  "windows_i686_gnu",
  "windows_i686_msvc",
  "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
  "windows_x86_64_msvc",
 ]
 
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.36.1"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
+checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.36.1"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
+checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.36.1"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
+checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.36.1"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
+checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.36.1"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
+checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
index 2b216ca072f0096832412085a0eae3fda4dc79ff..34117c2886febae43ecebb4f93cc498b2555ed58 100644 (file)
@@ -15,12 +15,14 @@ crate-type = ["dylib"]
 
 [dependencies]
 # These have to be in sync with each other
-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"
+cranelift-codegen = { version = "0.92", features = ["unwind", "all-arch"] }
+cranelift-frontend = { version = "0.92" }
+cranelift-module = { version = "0.92" }
+# NOTE vendored as src/cranelift_native.rs
+# FIXME revert back to the external crate with Cranelift 0.93
+#cranelift-native = { version = "0.92" }
+cranelift-jit = { version = "0.92", optional = true }
+cranelift-object = { version = "0.92" }
 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"] }
index 0e9c77244d4cc85d765371e97370db5c0adebf11..b87a9dc51e8d0f3f956e5fc69acb701a2c8e1ad3 100644 (file)
@@ -8,9 +8,9 @@ If not please open an issue.
 ## Building and testing
 
 ```bash
-$ git clone https://github.com/bjorn3/rustc_codegen_cranelift.git
+$ git clone https://github.com/bjorn3/rustc_codegen_cranelift
 $ cd rustc_codegen_cranelift
-$ ./y.rs prepare # download and patch sysroot src and install hyperfine for benchmarking
+$ ./y.rs prepare
 $ ./y.rs build
 ```
 
@@ -20,13 +20,12 @@ To run the test suite replace the last command with:
 $ ./test.sh
 ```
 
-This will implicitly build cg_clif too. Both `y.rs build` and `test.sh` accept a `--debug` argument to
-build in debug mode.
+For more docs on how to build and test see [build_system/usage.txt](build_system/usage.txt) or the help message of `./y.rs`.
 
-Alternatively you can download a pre built version from [GHA]. It is listed in the artifacts section
+Alternatively you can download a pre built version from [Github Actions]. It is listed in the artifacts section
 of workflow runs. Unfortunately due to GHA restrictions you need to be logged in to access it.
 
-[GHA]: https://github.com/bjorn3/rustc_codegen_cranelift/actions?query=branch%3Amaster+event%3Apush+is%3Asuccess
+[Github Actions]: https://github.com/bjorn3/rustc_codegen_cranelift/actions?query=branch%3Amaster+event%3Apush+is%3Asuccess
 
 ## Usage
 
@@ -53,7 +52,8 @@ configuration options.
 
 * Inline assembly ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1041))
     * On UNIX there is support for invoking an external assembler for `global_asm!` and `asm!`.
-* SIMD ([tracked here](https://github.com/bjorn3/rustc_codegen_cranelift/issues/171), some basic things work)
+* SIMD ([tracked here](https://github.com/bjorn3/rustc_codegen_cranelift/issues/171), `std::simd` fully works, `std::arch` is partially supported)
+* Unwinding on panics ([no cranelift support](https://github.com/bytecodealliance/wasmtime/issues/1677), `-Cpanic=abort` is enabled by default)
 
 ## License
 
index bba3210536ef7832e44ba9dbb5e46c3ee036baf6..24f15fc8521fee0dba322e556e6cbe49d3782238 100644 (file)
@@ -34,9 +34,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.0.77"
+version = "1.0.78"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
+checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
 
 [[package]]
 name = "cfg-if"
@@ -50,9 +50,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.85"
+version = "0.1.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13e81c6cd7ab79f51a0c927d22858d61ad12bd0b3865f0b13ece02a4486aeabb"
+checksum = "5dae98c88e576098d7ab13ebcb40cc43e5114b2beafe61a87cda9200649ff205"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -129,9 +129,9 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.138"
+version = "0.2.139"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
+checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
 dependencies = [
  "rustc-std-workspace-core",
 ]
index a081fdaa1c7e6475a727f764c033f07090b2b87e..dbee9be04eea6356920bbcde1c97583abb0c9cb7 100644 (file)
@@ -1,7 +1,6 @@
 use std::path::Path;
 
 use super::build_sysroot;
-use super::config;
 use super::path::Dirs;
 use super::prepare::GitRepo;
 use super::utils::{spawn_and_wait, CargoProject, Compiler};
 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) static ABI_CAFE: CargoProject =
+    CargoProject::new(&ABI_CAFE_REPO.source_dir(), "abi_cafe");
 
 pub(crate) fn run(
     channel: &str,
     sysroot_kind: SysrootKind,
     dirs: &Dirs,
     cg_clif_dylib: &Path,
-    host_triple: &str,
-    target_triple: &str,
+    bootstrap_host_compiler: &Compiler,
 ) {
-    if !config::get_bool("testsuite.abi-cafe") {
-        eprintln!("[SKIP] abi-cafe");
-        return;
-    }
-
-    if host_triple != target_triple {
-        eprintln!("[SKIP] abi-cafe (cross-compilation not supported)");
-        return;
-    }
-
     eprintln!("Building sysroot for abi-cafe");
     build_sysroot::build_sysroot(
         dirs,
         channel,
         sysroot_kind,
         cg_clif_dylib,
-        host_triple,
-        target_triple,
+        bootstrap_host_compiler,
+        bootstrap_host_compiler.triple.clone(),
     );
 
     eprintln!("Running abi-cafe");
 
     let pairs = ["rustc_calls_cgclif", "cgclif_calls_rustc", "cgclif_calls_cc", "cc_calls_cgclif"];
 
-    let mut cmd = ABI_CAFE.run(&Compiler::host(), dirs);
+    let mut cmd = ABI_CAFE.run(bootstrap_host_compiler, dirs);
     cmd.arg("--");
     cmd.arg("--pairs");
     cmd.args(pairs);
diff --git a/compiler/rustc_codegen_cranelift/build_system/bench.rs b/compiler/rustc_codegen_cranelift/build_system/bench.rs
new file mode 100644 (file)
index 0000000..01d44da
--- /dev/null
@@ -0,0 +1,97 @@
+use std::env;
+use std::fs;
+use std::path::Path;
+
+use super::path::{Dirs, RelPath};
+use super::prepare::GitRepo;
+use super::rustc_info::get_file_name;
+use super::utils::{hyperfine_command, is_ci, spawn_and_wait, CargoProject, Compiler};
+
+pub(crate) static SIMPLE_RAYTRACER_REPO: GitRepo = GitRepo::github(
+    "ebobby",
+    "simple-raytracer",
+    "804a7a21b9e673a482797aa289a18ed480e4d813",
+    "<none>",
+);
+
+// Use a separate target dir for the initial LLVM build to reduce unnecessary recompiles
+pub(crate) static SIMPLE_RAYTRACER_LLVM: CargoProject =
+    CargoProject::new(&SIMPLE_RAYTRACER_REPO.source_dir(), "simple_raytracer_llvm");
+
+pub(crate) static SIMPLE_RAYTRACER: CargoProject =
+    CargoProject::new(&SIMPLE_RAYTRACER_REPO.source_dir(), "simple_raytracer");
+
+pub(crate) fn benchmark(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
+    benchmark_simple_raytracer(dirs, bootstrap_host_compiler);
+}
+
+fn benchmark_simple_raytracer(dirs: &Dirs, bootstrap_host_compiler: &Compiler) {
+    if std::process::Command::new("hyperfine").output().is_err() {
+        eprintln!("Hyperfine not installed");
+        eprintln!("Hint: Try `cargo install hyperfine` to install hyperfine");
+        std::process::exit(1);
+    }
+
+    eprintln!("[LLVM BUILD] simple-raytracer");
+    let build_cmd = SIMPLE_RAYTRACER_LLVM.build(bootstrap_host_compiler, dirs);
+    spawn_and_wait(build_cmd);
+    fs::copy(
+        SIMPLE_RAYTRACER_LLVM
+            .target_dir(dirs)
+            .join(&bootstrap_host_compiler.triple)
+            .join("debug")
+            .join(get_file_name("main", "bin")),
+        RelPath::BUILD.to_path(dirs).join(get_file_name("raytracer_cg_llvm", "bin")),
+    )
+    .unwrap();
+
+    let run_runs = env::var("RUN_RUNS")
+        .unwrap_or(if is_ci() { "2" } else { "10" }.to_string())
+        .parse()
+        .unwrap();
+
+    eprintln!("[BENCH COMPILE] ebobby/simple-raytracer");
+    let cargo_clif =
+        RelPath::DIST.to_path(dirs).join(get_file_name("cargo_clif", "bin").replace('_', "-"));
+    let manifest_path = SIMPLE_RAYTRACER.manifest_path(dirs);
+    let target_dir = SIMPLE_RAYTRACER.target_dir(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(get_file_name("main", "bin")),
+        RelPath::BUILD.to_path(dirs).join(get_file_name("raytracer_cg_clif", "bin")),
+    )
+    .unwrap();
+
+    let mut bench_run = hyperfine_command(
+        0,
+        run_runs,
+        None,
+        Path::new(".").join(get_file_name("raytracer_cg_llvm", "bin")).to_str().unwrap(),
+        Path::new(".").join(get_file_name("raytracer_cg_clif", "bin")).to_str().unwrap(),
+    );
+    bench_run.current_dir(RelPath::BUILD.to_path(dirs));
+    spawn_and_wait(bench_run);
+}
index fde8ef424ccc5441e0198ef7b33b23c39dbe37bc..514404305a3fa0416635e45dc7ad0b9a6a34357a 100644 (file)
@@ -5,15 +5,15 @@
 use super::rustc_info::get_file_name;
 use super::utils::{is_ci, CargoProject, Compiler};
 
-static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif");
+pub(crate) static CG_CLIF: CargoProject = CargoProject::new(&RelPath::SOURCE, "cg_clif");
 
 pub(crate) fn build_backend(
     dirs: &Dirs,
     channel: &str,
-    host_triple: &str,
+    bootstrap_host_compiler: &Compiler,
     use_unstable_features: bool,
 ) -> PathBuf {
-    let mut cmd = CG_CLIF.build(&Compiler::host(), dirs);
+    let mut cmd = CG_CLIF.build(&bootstrap_host_compiler, dirs);
 
     cmd.env("CARGO_BUILD_INCREMENTAL", "true"); // Force incr comp even in release mode
 
@@ -25,6 +25,8 @@ pub(crate) fn build_backend(
 
         // Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway
         cmd.env("CARGO_BUILD_INCREMENTAL", "false");
+
+        cmd.env("CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS", "true");
     }
 
     if use_unstable_features {
@@ -46,7 +48,7 @@ pub(crate) fn build_backend(
 
     CG_CLIF
         .target_dir(dirs)
-        .join(host_triple)
+        .join(&bootstrap_host_compiler.triple)
         .join(channel)
         .join(get_file_name("rustc_codegen_cranelift", "dylib"))
 }
index cbbf09b9b97b8422ab06caff3b59b34c6352dfd4..bd04fdbe304a3031cf7995133a306a04744ff118 100644 (file)
@@ -1,31 +1,32 @@
 use std::fs;
-use std::path::Path;
+use std::path::{Path, PathBuf};
 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::{spawn_and_wait, try_hard_link, CargoProject, Compiler};
+use super::rustc_info::{get_file_name, get_rustc_version, get_toolchain_name};
+use super::utils::{remove_dir_if_exists, 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,
     cg_clif_dylib_src: &Path,
-    host_triple: &str,
-    target_triple: &str,
-) {
+    bootstrap_host_compiler: &Compiler,
+    target_triple: String,
+) -> Compiler {
     eprintln!("[BUILD] sysroot {:?}", sysroot_kind);
 
     DIST_DIR.ensure_fresh(dirs);
     BIN_DIR.ensure_exists(dirs);
     LIB_DIR.ensure_exists(dirs);
 
+    let is_native = bootstrap_host_compiler.triple == target_triple;
+
     // Copy the backend
     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
@@ -35,129 +36,169 @@ pub(crate) fn build_sysroot(
         LIB_DIR
     }
     .to_path(dirs)
-    .join(get_file_name("rustc_codegen_cranelift", "dylib"));
+    .join(cg_clif_dylib_src.file_name().unwrap());
     try_hard_link(cg_clif_dylib_src, &cg_clif_dylib_path);
 
     // Build and copy rustc and cargo wrappers
+    let wrapper_base_name = get_file_name("____", "bin");
+    let toolchain_name = get_toolchain_name();
     for wrapper in ["rustc-clif", "rustdoc-clif", "cargo-clif"] {
-        let wrapper_name = get_wrapper_file_name(wrapper, "bin");
+        let wrapper_name = wrapper_base_name.replace("____", wrapper);
 
-        let mut build_cargo_wrapper_cmd = Command::new("rustc");
+        let mut build_cargo_wrapper_cmd = Command::new(&bootstrap_host_compiler.rustc);
         build_cargo_wrapper_cmd
+            .env("TOOLCHAIN_NAME", toolchain_name.clone())
             .arg(RelPath::SCRIPTS.to_path(dirs).join(&format!("{wrapper}.rs")))
             .arg("-o")
             .arg(DIST_DIR.to_path(dirs).join(wrapper_name))
-            .arg("-g");
+            .arg("-Cstrip=debuginfo");
         spawn_and_wait(build_cargo_wrapper_cmd);
     }
 
-    let default_sysroot = super::rustc_info::get_default_sysroot();
+    let host = build_sysroot_for_triple(
+        dirs,
+        channel,
+        bootstrap_host_compiler.clone(),
+        &cg_clif_dylib_path,
+        sysroot_kind,
+    );
+    host.install_into_sysroot(&DIST_DIR.to_path(dirs));
 
-    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();
+    if !is_native {
+        build_sysroot_for_triple(
+            dirs,
+            channel,
+            {
+                let mut bootstrap_target_compiler = bootstrap_host_compiler.clone();
+                bootstrap_target_compiler.triple = target_triple.clone();
+                bootstrap_target_compiler.set_cross_linker_and_runner();
+                bootstrap_target_compiler
+            },
+            &cg_clif_dylib_path,
+            sysroot_kind,
+        )
+        .install_into_sysroot(&DIST_DIR.to_path(dirs));
+    }
 
-    if target_triple == "x86_64-pc-windows-gnu" {
-        if !default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib").exists() {
-            eprintln!(
-                "The x86_64-pc-windows-gnu target needs to be installed first before it is possible \
-                to compile a sysroot for it.",
-            );
-            process::exit(1);
+    // Copy std for the host to the lib dir. This is necessary for the jit mode to find
+    // libstd.
+    for lib in host.libs {
+        let filename = lib.file_name().unwrap().to_str().unwrap();
+        if filename.contains("std-") && !filename.contains(".rlib") {
+            try_hard_link(&lib, LIB_DIR.to_path(dirs).join(lib.file_name().unwrap()));
         }
-        for file in fs::read_dir(
-            default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib"),
-        )
-        .unwrap()
-        {
-            let file = file.unwrap().path();
-            if file.extension().map_or(true, |ext| ext.to_str().unwrap() != "o") {
-                continue; // only copy object files
-            }
-            try_hard_link(&file, target_rustlib_lib.join(file.file_name().unwrap()));
+    }
+
+    let mut target_compiler = {
+        let dirs: &Dirs = &dirs;
+        let rustc_clif =
+            RelPath::DIST.to_path(&dirs).join(wrapper_base_name.replace("____", "rustc-clif"));
+        let rustdoc_clif =
+            RelPath::DIST.to_path(&dirs).join(wrapper_base_name.replace("____", "rustdoc-clif"));
+
+        Compiler {
+            cargo: bootstrap_host_compiler.cargo.clone(),
+            rustc: rustc_clif.clone(),
+            rustdoc: rustdoc_clif.clone(),
+            rustflags: String::new(),
+            rustdocflags: String::new(),
+            triple: target_triple,
+            runner: vec![],
         }
+    };
+    if !is_native {
+        target_compiler.set_cross_linker_and_runner();
     }
+    target_compiler
+}
 
-    match sysroot_kind {
-        SysrootKind::None => {} // Nothing to do
-        SysrootKind::Llvm => {
-            for file in fs::read_dir(
-                default_sysroot.join("lib").join("rustlib").join(host_triple).join("lib"),
-            )
-            .unwrap()
-            {
-                let file = file.unwrap().path();
-                let file_name_str = file.file_name().unwrap().to_str().unwrap();
-                if (file_name_str.contains("rustc_")
-                    && !file_name_str.contains("rustc_std_workspace_")
-                    && !file_name_str.contains("rustc_demangle"))
-                    || file_name_str.contains("chalk")
-                    || file_name_str.contains("tracing")
-                    || file_name_str.contains("regex")
-                {
-                    // These are large crates that are part of the rustc-dev component and are not
-                    // necessary to run regular programs.
-                    continue;
-                }
-                try_hard_link(&file, host_rustlib_lib.join(file.file_name().unwrap()));
-            }
+struct SysrootTarget {
+    triple: String,
+    libs: Vec<PathBuf>,
+}
 
-            if target_triple != host_triple {
-                for file in fs::read_dir(
-                    default_sysroot.join("lib").join("rustlib").join(target_triple).join("lib"),
-                )
-                .unwrap()
-                {
-                    let file = file.unwrap().path();
-                    try_hard_link(&file, target_rustlib_lib.join(file.file_name().unwrap()));
-                }
-            }
+impl SysrootTarget {
+    fn install_into_sysroot(&self, sysroot: &Path) {
+        if self.libs.is_empty() {
+            return;
         }
-        SysrootKind::Clif => {
-            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 = 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_triple,
-                    &cg_clif_dylib_path,
-                    linker,
-                );
-            }
 
-            // Copy std for the host to the lib dir. This is necessary for the jit mode to find
-            // libstd.
-            for file in fs::read_dir(host_rustlib_lib).unwrap() {
-                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, LIB_DIR.to_path(dirs).join(file.file_name().unwrap()));
-                }
-            }
+        let target_rustlib_lib = sysroot.join("lib").join("rustlib").join(&self.triple).join("lib");
+        fs::create_dir_all(&target_rustlib_lib).unwrap();
+
+        for lib in &self.libs {
+            try_hard_link(lib, target_rustlib_lib.join(lib.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");
+pub(crate) static ORIG_BUILD_SYSROOT: RelPath = RelPath::SOURCE.join("build_sysroot");
+pub(crate) static BUILD_SYSROOT: RelPath = RelPath::DOWNLOAD.join("sysroot");
+pub(crate) static SYSROOT_RUSTC_VERSION: RelPath = BUILD_SYSROOT.join("rustc_version");
+pub(crate) static SYSROOT_SRC: RelPath = BUILD_SYSROOT.join("sysroot_src");
+pub(crate) static STANDARD_LIBRARY: CargoProject =
+    CargoProject::new(&BUILD_SYSROOT, "build_sysroot");
+pub(crate) static RTSTARTUP_SYSROOT: RelPath = RelPath::BUILD.join("rtstartup");
 
+#[must_use]
+fn build_sysroot_for_triple(
+    dirs: &Dirs,
+    channel: &str,
+    compiler: Compiler,
+    cg_clif_dylib_path: &Path,
+    sysroot_kind: SysrootKind,
+) -> SysrootTarget {
+    match sysroot_kind {
+        SysrootKind::None => build_rtstartup(dirs, &compiler)
+            .unwrap_or(SysrootTarget { triple: compiler.triple, libs: vec![] }),
+        SysrootKind::Llvm => build_llvm_sysroot_for_triple(compiler),
+        SysrootKind::Clif => {
+            build_clif_sysroot_for_triple(dirs, channel, compiler, &cg_clif_dylib_path)
+        }
+    }
+}
+
+#[must_use]
+fn build_llvm_sysroot_for_triple(compiler: Compiler) -> SysrootTarget {
+    let default_sysroot = super::rustc_info::get_default_sysroot(&compiler.rustc);
+
+    let mut target_libs = SysrootTarget { triple: compiler.triple, libs: vec![] };
+
+    for entry in fs::read_dir(
+        default_sysroot.join("lib").join("rustlib").join(&target_libs.triple).join("lib"),
+    )
+    .unwrap()
+    {
+        let entry = entry.unwrap();
+        if entry.file_type().unwrap().is_dir() {
+            continue;
+        }
+        let file = entry.path();
+        let file_name_str = file.file_name().unwrap().to_str().unwrap();
+        if (file_name_str.contains("rustc_")
+            && !file_name_str.contains("rustc_std_workspace_")
+            && !file_name_str.contains("rustc_demangle"))
+            || file_name_str.contains("chalk")
+            || file_name_str.contains("tracing")
+            || file_name_str.contains("regex")
+        {
+            // These are large crates that are part of the rustc-dev component and are not
+            // necessary to run regular programs.
+            continue;
+        }
+        target_libs.libs.push(file);
+    }
+
+    target_libs
+}
+
+#[must_use]
 fn build_clif_sysroot_for_triple(
     dirs: &Dirs,
     channel: &str,
-    triple: &str,
+    mut compiler: Compiler,
     cg_clif_dylib_path: &Path,
-    linker: Option<&str>,
-) {
+) -> SysrootTarget {
     match fs::read_to_string(SYSROOT_RUSTC_VERSION.to_path(dirs)) {
         Err(e) => {
             eprintln!("Failed to get rustc version for patched sysroot source: {}", e);
@@ -165,7 +206,7 @@ fn build_clif_sysroot_for_triple(
             process::exit(1);
         }
         Ok(source_version) => {
-            let rustc_version = get_rustc_version();
+            let rustc_version = get_rustc_version(&compiler.rustc);
             if source_version != rustc_version {
                 eprintln!("The patched sysroot source is outdated");
                 eprintln!("Source version: {}", source_version.trim());
@@ -176,29 +217,32 @@ fn build_clif_sysroot_for_triple(
         }
     }
 
-    let build_dir = STANDARD_LIBRARY.target_dir(dirs).join(triple).join(channel);
+    let mut target_libs = SysrootTarget { triple: compiler.triple.clone(), libs: vec![] };
+
+    if let Some(rtstartup_target_libs) = build_rtstartup(dirs, &compiler) {
+        rtstartup_target_libs.install_into_sysroot(&RTSTARTUP_SYSROOT.to_path(dirs));
+
+        target_libs.libs.extend(rtstartup_target_libs.libs);
+    }
+
+    let build_dir = STANDARD_LIBRARY.target_dir(dirs).join(&compiler.triple).join(channel);
 
     if !super::config::get_bool("keep_sysroot") {
         // Cleanup the deps dir, but keep build scripts and the incremental cache for faster
         // recompilation as they are not affected by changes in cg_clif.
-        if build_dir.join("deps").exists() {
-            fs::remove_dir_all(build_dir.join("deps")).unwrap();
-        }
+        remove_dir_if_exists(&build_dir.join("deps"));
     }
 
     // Build sysroot
-    let mut rustflags = "-Zforce-unstable-if-unmarked -Cpanic=abort".to_string();
+    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={}", DIST_DIR.to_path(dirs).to_str().unwrap()));
+    // Necessary for MinGW to find rsbegin.o and rsend.o
+    rustflags
+        .push_str(&format!(" --sysroot={}", RTSTARTUP_SYSROOT.to_path(dirs).to_str().unwrap()));
     if channel == "release" {
         rustflags.push_str(" -Zmir-opt-level=3");
     }
-    if let Some(linker) = linker {
-        use std::fmt::Write;
-        write!(rustflags, " -Clinker={}", linker).unwrap();
-    }
-    let mut compiler = Compiler::with_triple(triple.to_owned());
-    compiler.rustflags = rustflags;
+    compiler.rustflags += &rustflags;
     let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs);
     if channel == "release" {
         build_cmd.arg("--release");
@@ -206,7 +250,6 @@ fn build_clif_sysroot_for_triple(
     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(build_dir.join("deps")).unwrap() {
         let entry = entry.unwrap();
         if let Some(ext) = entry.path().extension() {
@@ -216,9 +259,35 @@ fn build_clif_sysroot_for_triple(
         } else {
             continue;
         };
-        try_hard_link(
-            entry.path(),
-            RUSTLIB_DIR.to_path(dirs).join(triple).join("lib").join(entry.file_name()),
-        );
+        target_libs.libs.push(entry.path());
+    }
+
+    target_libs
+}
+
+fn build_rtstartup(dirs: &Dirs, compiler: &Compiler) -> Option<SysrootTarget> {
+    if !compiler.triple.ends_with("windows-gnu") {
+        return None;
     }
+
+    RTSTARTUP_SYSROOT.ensure_fresh(dirs);
+
+    let rtstartup_src = SYSROOT_SRC.to_path(dirs).join("library").join("rtstartup");
+    let mut target_libs = SysrootTarget { triple: compiler.triple.clone(), libs: vec![] };
+
+    for file in ["rsbegin", "rsend"] {
+        let obj = RTSTARTUP_SYSROOT.to_path(dirs).join(format!("{file}.o"));
+        let mut build_rtstartup_cmd = Command::new(&compiler.rustc);
+        build_rtstartup_cmd
+            .arg("--target")
+            .arg(&compiler.triple)
+            .arg("--emit=obj")
+            .arg("-o")
+            .arg(&obj)
+            .arg(rtstartup_src.join(format!("{file}.rs")));
+        spawn_and_wait(build_rtstartup_cmd);
+        target_libs.libs.push(obj.clone());
+    }
+
+    Some(target_libs)
 }
index 1afc9a55c73b5318bbc9ed006899c4f5ab3647c3..8dcbe8de189b25a0c31edb7a8fe5525a5826a359 100644 (file)
@@ -2,9 +2,10 @@
 use std::path::PathBuf;
 use std::process;
 
-use self::utils::is_ci;
+use self::utils::{is_ci, Compiler};
 
 mod abi_cafe;
+mod bench;
 mod build_backend;
 mod build_sysroot;
 mod config;
 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!("{}", include_str!("usage.txt"));
 }
 
 macro_rules! arg_error {
@@ -54,6 +32,8 @@ enum Command {
     Prepare,
     Build,
     Test,
+    AbiCafe,
+    Bench,
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -64,12 +44,17 @@ pub(crate) enum SysrootKind {
 }
 
 pub fn main() {
-    env::set_var("CG_CLIF_DISPLAY_CG_TIME", "1");
+    if env::var("RUST_BACKTRACE").is_err() {
+        env::set_var("RUST_BACKTRACE", "1");
+    }
     env::set_var("CG_CLIF_DISABLE_INCR_CACHE", "1");
 
     if is_ci() {
         // Disabling incr comp reduces cache size and incr comp doesn't save as much on CI anyway
         env::set_var("CARGO_BUILD_INCREMENTAL", "false");
+
+        // Enable the Cranelift verifier
+        env::set_var("CG_CLIF_ENABLE_VERIFIER", "1");
     }
 
     let mut args = env::args().skip(1);
@@ -77,6 +62,8 @@ pub fn main() {
         Some("prepare") => Command::Prepare,
         Some("build") => Command::Build,
         Some("test") => Command::Test,
+        Some("abi-cafe") => Command::AbiCafe,
+        Some("bench") => Command::Bench,
         Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag),
         Some(command) => arg_error!("Unknown command {}", command),
         None => {
@@ -112,24 +99,16 @@ pub fn main() {
         }
     }
 
-    let host_triple = if let Ok(host_triple) = std::env::var("HOST_TRIPLE") {
-        host_triple
-    } else if let Some(host_triple) = config::get_value("host") {
-        host_triple
-    } else {
-        rustc_info::get_host_triple()
-    };
-    let target_triple = if let Ok(target_triple) = std::env::var("TARGET_TRIPLE") {
-        if target_triple != "" {
-            target_triple
-        } else {
-            host_triple.clone() // Empty target triple can happen on GHA
-        }
-    } else if let Some(target_triple) = config::get_value("target") {
-        target_triple
-    } else {
-        host_triple.clone()
-    };
+    let bootstrap_host_compiler = Compiler::bootstrap_with_triple(
+        std::env::var("HOST_TRIPLE")
+            .ok()
+            .or_else(|| config::get_value("host"))
+            .unwrap_or_else(|| rustc_info::get_host_triple()),
+    );
+    let target_triple = std::env::var("TARGET_TRIPLE")
+        .ok()
+        .or_else(|| config::get_value("target"))
+        .unwrap_or_else(|| bootstrap_host_compiler.triple.clone());
 
     // FIXME allow changing the location of these dirs using cli arguments
     let current_dir = std::env::current_dir().unwrap();
@@ -157,8 +136,15 @@ pub fn main() {
         process::exit(0);
     }
 
-    let cg_clif_dylib =
-        build_backend::build_backend(&dirs, channel, &host_triple, use_unstable_features);
+    env::set_var("RUSTC", "rustc_should_be_set_explicitly");
+    env::set_var("RUSTDOC", "rustdoc_should_be_set_explicitly");
+
+    let cg_clif_dylib = build_backend::build_backend(
+        &dirs,
+        channel,
+        &bootstrap_host_compiler,
+        use_unstable_features,
+    );
     match command {
         Command::Prepare => {
             // Handled above
@@ -169,28 +155,37 @@ pub fn main() {
                 channel,
                 sysroot_kind,
                 &cg_clif_dylib,
-                &host_triple,
-                &target_triple,
+                &bootstrap_host_compiler,
+                target_triple.clone(),
             );
-
-            abi_cafe::run(
+        }
+        Command::AbiCafe => {
+            if bootstrap_host_compiler.triple != target_triple {
+                eprintln!("Abi-cafe doesn't support cross-compilation");
+                process::exit(1);
+            }
+            abi_cafe::run(channel, sysroot_kind, &dirs, &cg_clif_dylib, &bootstrap_host_compiler);
+        }
+        Command::Build => {
+            build_sysroot::build_sysroot(
+                &dirs,
                 channel,
                 sysroot_kind,
-                &dirs,
                 &cg_clif_dylib,
-                &host_triple,
-                &target_triple,
+                &bootstrap_host_compiler,
+                target_triple,
             );
         }
-        Command::Build => {
+        Command::Bench => {
             build_sysroot::build_sysroot(
                 &dirs,
                 channel,
                 sysroot_kind,
                 &cg_clif_dylib,
-                &host_triple,
-                &target_triple,
+                &bootstrap_host_compiler,
+                target_triple,
             );
+            bench::benchmark(&dirs, &bootstrap_host_compiler);
         }
     }
 }
index e93981f1d64d369b28672c0e61ff5a533c271a23..3290723005dd92b939486489e4acda090b0a8ac0 100644 (file)
@@ -1,6 +1,8 @@
 use std::fs;
 use std::path::PathBuf;
 
+use super::utils::remove_dir_if_exists;
+
 #[derive(Debug, Clone)]
 pub(crate) struct Dirs {
     pub(crate) source_dir: PathBuf,
@@ -42,7 +44,6 @@ impl RelPath {
     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 {
@@ -62,9 +63,7 @@ pub(crate) fn ensure_exists(&self, dirs: &Dirs) {
 
     pub(crate) fn ensure_fresh(&self, dirs: &Dirs) {
         let path = self.to_path(dirs);
-        if path.exists() {
-            fs::remove_dir_all(&path).unwrap();
-        }
+        remove_dir_if_exists(&path);
         fs::create_dir_all(path).unwrap();
     }
 }
index 8ac67e8f9422823090a97ffab654c0da5a848e12..f25a81dc23459f8e93e4204eb32efb2c80df12e8 100644 (file)
@@ -3,73 +3,55 @@
 use std::path::{Path, PathBuf};
 use std::process::Command;
 
-use super::build_sysroot::{SYSROOT_RUSTC_VERSION, SYSROOT_SRC};
+use super::build_sysroot::{BUILD_SYSROOT, ORIG_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::{copy_dir_recursively, spawn_and_wait, Compiler};
+use super::rustc_info::{get_default_sysroot, get_rustc_version};
+use super::utils::{copy_dir_recursively, git_command, retry_spawn_and_wait, spawn_and_wait};
 
 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(RelPath::DOWNLOAD.to_path(dirs)).unwrap();
+    RelPath::DOWNLOAD.ensure_fresh(dirs);
 
-    prepare_sysroot(dirs);
+    spawn_and_wait(super::build_backend::CG_CLIF.fetch("cargo", dirs));
 
-    // FIXME maybe install this only locally?
-    eprintln!("[INSTALL] hyperfine");
-    Command::new("cargo")
-        .arg("install")
-        .arg("hyperfine")
-        .env_remove("CARGO_TARGET_DIR")
-        .spawn()
-        .unwrap()
-        .wait()
-        .unwrap();
+    prepare_sysroot(dirs);
+    spawn_and_wait(super::build_sysroot::STANDARD_LIBRARY.fetch("cargo", dirs));
+    spawn_and_wait(super::tests::LIBCORE_TESTS.fetch("cargo", dirs));
 
     super::abi_cafe::ABI_CAFE_REPO.fetch(dirs);
+    spawn_and_wait(super::abi_cafe::ABI_CAFE.fetch("cargo", dirs));
     super::tests::RAND_REPO.fetch(dirs);
+    spawn_and_wait(super::tests::RAND.fetch("cargo", dirs));
     super::tests::REGEX_REPO.fetch(dirs);
+    spawn_and_wait(super::tests::REGEX.fetch("cargo", dirs));
     super::tests::PORTABLE_SIMD_REPO.fetch(dirs);
-    super::tests::SIMPLE_RAYTRACER_REPO.fetch(dirs);
-
-    eprintln!("[LLVM BUILD] simple-raytracer");
-    let host_compiler = Compiler::host();
-    let build_cmd = super::tests::SIMPLE_RAYTRACER.build(&host_compiler, dirs);
-    spawn_and_wait(build_cmd);
-    fs::copy(
-        super::tests::SIMPLE_RAYTRACER
-            .target_dir(dirs)
-            .join(&host_compiler.triple)
-            .join("debug")
-            .join(get_file_name("main", "bin")),
-        RelPath::BUILD.to_path(dirs).join(get_file_name("raytracer_cg_llvm", "bin")),
-    )
-    .unwrap();
+    spawn_and_wait(super::tests::PORTABLE_SIMD.fetch("cargo", dirs));
+    super::bench::SIMPLE_RAYTRACER_REPO.fetch(dirs);
+    spawn_and_wait(super::bench::SIMPLE_RAYTRACER.fetch("cargo", dirs));
 }
 
 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 = SYSROOT_SRC;
-
+    let sysroot_src_orig = get_default_sysroot(Path::new("rustc")).join("lib/rustlib/src/rust");
     assert!(sysroot_src_orig.exists());
 
-    sysroot_src.ensure_fresh(dirs);
-    fs::create_dir_all(sysroot_src.to_path(dirs).join("library")).unwrap();
     eprintln!("[COPY] sysroot src");
+
+    // FIXME ensure builds error out or update the copy if any of the files copied here change
+    BUILD_SYSROOT.ensure_fresh(dirs);
+    copy_dir_recursively(&ORIG_BUILD_SYSROOT.to_path(dirs), &BUILD_SYSROOT.to_path(dirs));
+
+    fs::create_dir_all(SYSROOT_SRC.to_path(dirs).join("library")).unwrap();
     copy_dir_recursively(
         &sysroot_src_orig.join("library"),
-        &sysroot_src.to_path(dirs).join("library"),
+        &SYSROOT_SRC.to_path(dirs).join("library"),
     );
 
-    let rustc_version = get_rustc_version();
+    let rustc_version = get_rustc_version(Path::new("rustc"));
     fs::write(SYSROOT_RUSTC_VERSION.to_path(dirs), &rustc_version).unwrap();
 
     eprintln!("[GIT] init");
-    init_git_repo(&sysroot_src.to_path(dirs));
+    init_git_repo(&SYSROOT_SRC.to_path(dirs));
 
-    apply_patches(dirs, "sysroot", &sysroot_src.to_path(dirs));
+    apply_patches(dirs, "sysroot", &SYSROOT_SRC.to_path(dirs));
 }
 
 pub(crate) struct GitRepo {
@@ -118,14 +100,14 @@ fn fetch(&self, dirs: &Dirs) {
 fn clone_repo(download_dir: &Path, repo: &str, rev: &str) {
     eprintln!("[CLONE] {}", repo);
     // Ignore exit code as the repo may already have been checked out
-    Command::new("git").arg("clone").arg(repo).arg(&download_dir).spawn().unwrap().wait().unwrap();
+    git_command(None, "clone").arg(repo).arg(download_dir).spawn().unwrap().wait().unwrap();
 
-    let mut clean_cmd = Command::new("git");
-    clean_cmd.arg("checkout").arg("--").arg(".").current_dir(&download_dir);
+    let mut clean_cmd = git_command(download_dir, "checkout");
+    clean_cmd.arg("--").arg(".");
     spawn_and_wait(clean_cmd);
 
-    let mut checkout_cmd = Command::new("git");
-    checkout_cmd.arg("checkout").arg("-q").arg(rev).current_dir(download_dir);
+    let mut checkout_cmd = git_command(download_dir, "checkout");
+    checkout_cmd.arg("-q").arg(rev);
     spawn_and_wait(checkout_cmd);
 }
 
@@ -149,8 +131,22 @@ fn clone_repo_shallow_github(dirs: &Dirs, download_dir: &Path, user: &str, repo:
 
     // Download zip archive
     let mut download_cmd = Command::new("curl");
-    download_cmd.arg("--location").arg("--output").arg(&archive_file).arg(archive_url);
-    spawn_and_wait(download_cmd);
+    download_cmd
+        .arg("--max-time")
+        .arg("600")
+        .arg("-y")
+        .arg("30")
+        .arg("-Y")
+        .arg("10")
+        .arg("--connect-timeout")
+        .arg("30")
+        .arg("--continue-at")
+        .arg("-")
+        .arg("--location")
+        .arg("--output")
+        .arg(&archive_file)
+        .arg(archive_url);
+    retry_spawn_and_wait(5, download_cmd);
 
     // Unpack tar archive
     let mut unpack_cmd = Command::new("tar");
@@ -167,25 +163,16 @@ fn clone_repo_shallow_github(dirs: &Dirs, download_dir: &Path, user: &str, repo:
 }
 
 fn init_git_repo(repo_dir: &Path) {
-    let mut git_init_cmd = Command::new("git");
-    git_init_cmd.arg("init").arg("-q").current_dir(repo_dir);
+    let mut git_init_cmd = git_command(repo_dir, "init");
+    git_init_cmd.arg("-q");
     spawn_and_wait(git_init_cmd);
 
-    let mut git_add_cmd = Command::new("git");
-    git_add_cmd.arg("add").arg(".").current_dir(repo_dir);
+    let mut git_add_cmd = git_command(repo_dir, "add");
+    git_add_cmd.arg(".");
     spawn_and_wait(git_add_cmd);
 
-    let mut git_commit_cmd = Command::new("git");
-    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);
+    let mut git_commit_cmd = git_command(repo_dir, "commit");
+    git_commit_cmd.arg("-m").arg("Initial commit").arg("-q");
     spawn_and_wait(git_commit_cmd);
 }
 
@@ -220,16 +207,8 @@ fn apply_patches(dirs: &Dirs, crate_name: &str, target_dir: &Path) {
             target_dir.file_name().unwrap(),
             patch.file_name().unwrap()
         );
-        let mut apply_patch_cmd = Command::new("git");
-        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);
+        let mut apply_patch_cmd = git_command(target_dir, "am");
+        apply_patch_cmd.arg(patch).arg("-q");
         spawn_and_wait(apply_patch_cmd);
     }
 }
index 8e5ab688e131b35325af4fb83a3387b8c6228449..a70453b4422898e31f0030f1613cf7877260e481 100644 (file)
@@ -1,9 +1,9 @@
 use std::path::{Path, PathBuf};
 use std::process::{Command, Stdio};
 
-pub(crate) fn get_rustc_version() -> String {
+pub(crate) fn get_rustc_version(rustc: &Path) -> String {
     let version_info =
-        Command::new("rustc").stderr(Stdio::inherit()).args(&["-V"]).output().unwrap().stdout;
+        Command::new(rustc).stderr(Stdio::inherit()).args(&["-V"]).output().unwrap().stdout;
     String::from_utf8(version_info).unwrap()
 }
 
@@ -23,6 +23,16 @@ pub(crate) fn get_host_triple() -> String {
         .to_owned()
 }
 
+pub(crate) fn get_toolchain_name() -> String {
+    let active_toolchain = Command::new("rustup")
+        .stderr(Stdio::inherit())
+        .args(&["show", "active-toolchain"])
+        .output()
+        .unwrap()
+        .stdout;
+    String::from_utf8(active_toolchain).unwrap().trim().split_once(' ').unwrap().0.to_owned()
+}
+
 pub(crate) fn get_cargo_path() -> PathBuf {
     let cargo_path = Command::new("rustup")
         .stderr(Stdio::inherit())
@@ -53,8 +63,8 @@ pub(crate) fn get_rustdoc_path() -> PathBuf {
     Path::new(String::from_utf8(rustc_path).unwrap().trim()).to_owned()
 }
 
-pub(crate) fn get_default_sysroot() -> PathBuf {
-    let default_sysroot = Command::new("rustc")
+pub(crate) fn get_default_sysroot(rustc: &Path) -> PathBuf {
+    let default_sysroot = Command::new(rustc)
         .stderr(Stdio::inherit())
         .args(&["--print", "sysroot"])
         .output()
@@ -83,12 +93,3 @@ pub(crate) fn get_file_name(crate_name: &str, crate_type: &str) -> String {
     assert!(file_name.contains(crate_name));
     file_name
 }
-
-/// Similar to `get_file_name`, but converts any dashes (`-`) in the `crate_name` to
-/// underscores (`_`). This is specially made for the rustc and cargo wrappers
-/// which have a dash in the name, and that is not allowed in a crate name.
-pub(crate) fn get_wrapper_file_name(crate_name: &str, crate_type: &str) -> String {
-    let crate_name = crate_name.replace('-', "_");
-    let wrapper_name = get_file_name(&crate_name, crate_type);
-    wrapper_name.replace('_', "-")
-}
index 1c372736ed65d9121dccf04ae5bcf504d45127bc..dcfadd737566e20d8a76f0fb8bf393e9b27eb654 100644 (file)
@@ -1,11 +1,10 @@
-use super::build_sysroot;
+use super::bench::SIMPLE_RAYTRACER;
+use super::build_sysroot::{self, SYSROOT_SRC};
 use super::config;
 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::rustc_info::get_host_triple;
+use super::utils::{spawn_and_wait, spawn_and_wait_with_input, CargoProject, Compiler};
 use super::SysrootKind;
 use std::env;
 use std::ffi::OsStr;
 
 struct TestCase {
     config: &'static str,
-    func: &'static dyn Fn(&TestRunner),
+    cmd: TestCaseCmd,
+}
+
+enum TestCaseCmd {
+    Custom { func: &'static dyn Fn(&TestRunner) },
+    BuildLib { source: &'static str, crate_types: &'static str },
+    BuildBinAndRun { source: &'static str, args: &'static [&'static str] },
+    JitBin { source: &'static str, args: &'static str },
 }
 
 impl TestCase {
-    const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
-        Self { config, func }
+    // FIXME reduce usage of custom test case commands
+    const fn custom(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
+        Self { config, cmd: TestCaseCmd::Custom { func } }
+    }
+
+    const fn build_lib(
+        config: &'static str,
+        source: &'static str,
+        crate_types: &'static str,
+    ) -> Self {
+        Self { config, cmd: TestCaseCmd::BuildLib { source, crate_types } }
+    }
+
+    const fn build_bin_and_run(
+        config: &'static str,
+        source: &'static str,
+        args: &'static [&'static str],
+    ) -> Self {
+        Self { config, cmd: TestCaseCmd::BuildBinAndRun { source, args } }
+    }
+
+    const fn jit_bin(config: &'static str, source: &'static str, args: &'static str) -> Self {
+        Self { config, cmd: TestCaseCmd::JitBin { source, args } }
     }
 }
 
 const NO_SYSROOT_SUITE: &[TestCase] = &[
-    TestCase::new("build.mini_core", &|runner| {
-        runner.run_rustc([
-            "example/mini_core.rs",
-            "--crate-name",
-            "mini_core",
-            "--crate-type",
-            "lib,dylib",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-    }),
-    TestCase::new("build.example", &|runner| {
-        runner.run_rustc([
-            "example/example.rs",
-            "--crate-type",
-            "lib",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-    }),
-    TestCase::new("jit.mini_core_hello_world", &|runner| {
-        let mut jit_cmd = runner.rustc_command([
-            "-Zunstable-options",
-            "-Cllvm-args=mode=jit",
-            "-Cprefer-dynamic",
-            "example/mini_core_hello_world.rs",
-            "--cfg",
-            "jit",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd");
-        spawn_and_wait(jit_cmd);
-
-        eprintln!("[JIT-lazy] mini_core_hello_world");
-        let mut jit_cmd = runner.rustc_command([
-            "-Zunstable-options",
-            "-Cllvm-args=mode=jit-lazy",
-            "-Cprefer-dynamic",
-            "example/mini_core_hello_world.rs",
-            "--cfg",
-            "jit",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        jit_cmd.env("CG_CLIF_JIT_ARGS", "abc bcd");
-        spawn_and_wait(jit_cmd);
-    }),
-    TestCase::new("aot.mini_core_hello_world", &|runner| {
-        runner.run_rustc([
-            "example/mini_core_hello_world.rs",
-            "--crate-name",
-            "mini_core_hello_world",
-            "--crate-type",
-            "bin",
-            "-g",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        runner.run_out_command("mini_core_hello_world", ["abc", "bcd"]);
-    }),
+    TestCase::build_lib("build.mini_core", "example/mini_core.rs", "lib,dylib"),
+    TestCase::build_lib("build.example", "example/example.rs", "lib"),
+    TestCase::jit_bin("jit.mini_core_hello_world", "example/mini_core_hello_world.rs", "abc bcd"),
+    TestCase::build_bin_and_run(
+        "aot.mini_core_hello_world",
+        "example/mini_core_hello_world.rs",
+        &["abc", "bcd"],
+    ),
 ];
 
 const BASE_SYSROOT_SUITE: &[TestCase] = &[
-    TestCase::new("aot.arbitrary_self_types_pointers_and_wrappers", &|runner| {
-        runner.run_rustc([
-            "example/arbitrary_self_types_pointers_and_wrappers.rs",
-            "--crate-name",
-            "arbitrary_self_types_pointers_and_wrappers",
-            "--crate-type",
-            "bin",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        runner.run_out_command("arbitrary_self_types_pointers_and_wrappers", []);
-    }),
-    TestCase::new("aot.issue_91827_extern_types", &|runner| {
-        runner.run_rustc([
-            "example/issue-91827-extern-types.rs",
-            "--crate-name",
-            "issue_91827_extern_types",
-            "--crate-type",
-            "bin",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        runner.run_out_command("issue_91827_extern_types", []);
-    }),
-    TestCase::new("build.alloc_system", &|runner| {
-        runner.run_rustc([
-            "example/alloc_system.rs",
-            "--crate-type",
-            "lib",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-    }),
-    TestCase::new("aot.alloc_example", &|runner| {
-        runner.run_rustc([
-            "example/alloc_example.rs",
-            "--crate-type",
-            "bin",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        runner.run_out_command("alloc_example", []);
-    }),
-    TestCase::new("jit.std_example", &|runner| {
-        runner.run_rustc([
-            "-Zunstable-options",
-            "-Cllvm-args=mode=jit",
-            "-Cprefer-dynamic",
-            "example/std_example.rs",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-
-        eprintln!("[JIT-lazy] std_example");
-        runner.run_rustc([
-            "-Zunstable-options",
-            "-Cllvm-args=mode=jit-lazy",
-            "-Cprefer-dynamic",
-            "example/std_example.rs",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-    }),
-    TestCase::new("aot.std_example", &|runner| {
-        runner.run_rustc([
-            "example/std_example.rs",
-            "--crate-type",
-            "bin",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        runner.run_out_command("std_example", ["arg"]);
-    }),
-    TestCase::new("aot.dst_field_align", &|runner| {
-        runner.run_rustc([
-            "example/dst-field-align.rs",
-            "--crate-name",
-            "dst_field_align",
-            "--crate-type",
-            "bin",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        runner.run_out_command("dst_field_align", []);
-    }),
-    TestCase::new("aot.subslice-patterns-const-eval", &|runner| {
-        runner.run_rustc([
-            "example/subslice-patterns-const-eval.rs",
-            "--crate-type",
-            "bin",
-            "-Cpanic=abort",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        runner.run_out_command("subslice-patterns-const-eval", []);
-    }),
-    TestCase::new("aot.track-caller-attribute", &|runner| {
-        runner.run_rustc([
-            "example/track-caller-attribute.rs",
-            "--crate-type",
-            "bin",
-            "-Cpanic=abort",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        runner.run_out_command("track-caller-attribute", []);
-    }),
-    TestCase::new("aot.float-minmax-pass", &|runner| {
-        runner.run_rustc([
-            "example/float-minmax-pass.rs",
-            "--crate-type",
-            "bin",
-            "-Cpanic=abort",
-            "--target",
-            &runner.target_compiler.triple,
-        ]);
-        runner.run_out_command("float-minmax-pass", []);
-    }),
-    TestCase::new("aot.mod_bench", &|runner| {
-        runner.run_rustc([
-            "example/mod_bench.rs",
-            "--crate-type",
-            "bin",
-            "--target",
-            &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", []);
-    }),
+    TestCase::build_bin_and_run(
+        "aot.arbitrary_self_types_pointers_and_wrappers",
+        "example/arbitrary_self_types_pointers_and_wrappers.rs",
+        &[],
+    ),
+    TestCase::build_bin_and_run(
+        "aot.issue_91827_extern_types",
+        "example/issue-91827-extern-types.rs",
+        &[],
+    ),
+    TestCase::build_lib("build.alloc_system", "example/alloc_system.rs", "lib"),
+    TestCase::build_bin_and_run("aot.alloc_example", "example/alloc_example.rs", &[]),
+    TestCase::jit_bin("jit.std_example", "example/std_example.rs", ""),
+    TestCase::build_bin_and_run("aot.std_example", "example/std_example.rs", &["arg"]),
+    TestCase::build_bin_and_run("aot.dst_field_align", "example/dst-field-align.rs", &[]),
+    TestCase::build_bin_and_run(
+        "aot.subslice-patterns-const-eval",
+        "example/subslice-patterns-const-eval.rs",
+        &[],
+    ),
+    TestCase::build_bin_and_run(
+        "aot.track-caller-attribute",
+        "example/track-caller-attribute.rs",
+        &[],
+    ),
+    TestCase::build_bin_and_run("aot.float-minmax-pass", "example/float-minmax-pass.rs", &[]),
+    TestCase::build_bin_and_run("aot.mod_bench", "example/mod_bench.rs", &[]),
+    TestCase::build_bin_and_run("aot.issue-72793", "example/issue-72793.rs", &[]),
 ];
 
 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 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 REGEX: CargoProject = CargoProject::new(&REGEX_REPO.source_dir(), "regex");
 
 pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github(
     "rust-lang",
     "portable-simd",
-    "d5cd4a8112d958bd3a252327e0d069a6363249bd",
+    "582239ac3b32007613df04d7ffa78dc30f4c5645",
     "portable-simd",
 );
 
-static PORTABLE_SIMD: CargoProject =
+pub(crate) 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");
+pub(crate) static LIBCORE_TESTS: CargoProject =
+    CargoProject::new(&SYSROOT_SRC.join("library/core/tests"), "core_tests");
 
 const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
-    TestCase::new("test.rust-random/rand", &|runner| {
-        spawn_and_wait(RAND.clean(&runner.target_compiler.cargo, &runner.dirs));
+    TestCase::custom("test.rust-random/rand", &|runner| {
+        RAND.clean(&runner.dirs);
 
         if runner.is_native {
             eprintln!("[TEST] rust-random/rand");
@@ -280,60 +134,12 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             spawn_and_wait(build_cmd);
         }
     }),
-    TestCase::new("bench.simple-raytracer", &|runner| {
-        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::custom("test.simple-raytracer", &|runner| {
+        SIMPLE_RAYTRACER.clean(&runner.dirs);
+        spawn_and_wait(SIMPLE_RAYTRACER.build(&runner.target_compiler, &runner.dirs));
     }),
-    TestCase::new("test.libcore", &|runner| {
-        spawn_and_wait(LIBCORE_TESTS.clean(&runner.host_compiler.cargo, &runner.dirs));
+    TestCase::custom("test.libcore", &|runner| {
+        LIBCORE_TESTS.clean(&runner.dirs);
 
         if runner.is_native {
             spawn_and_wait(LIBCORE_TESTS.test(&runner.target_compiler, &runner.dirs));
@@ -344,8 +150,8 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             spawn_and_wait(build_cmd);
         }
     }),
-    TestCase::new("test.regex-shootout-regex-dna", &|runner| {
-        spawn_and_wait(REGEX.clean(&runner.target_compiler.cargo, &runner.dirs));
+    TestCase::custom("test.regex-shootout-regex-dna", &|runner| {
+        REGEX.clean(&runner.dirs);
 
         // newer aho_corasick versions throw a deprecation warning
         let lint_rust_flags = format!("{} --cap-lints warn", runner.target_compiler.rustflags);
@@ -364,9 +170,10 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
                 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 expected = fs::read_to_string(
+                REGEX.source_dir(&runner.dirs).join("examples").join("regexdna-output.txt"),
+            )
+            .unwrap();
 
             let output = spawn_and_wait_with_input(run_cmd, input);
             // Make sure `[codegen mono items] start` doesn't poison the diff
@@ -379,27 +186,16 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
 
             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);
-                }
+                println!("Output files don't match!");
+                println!("Expected Output:\n{}", expected);
+                println!("Actual Output:\n{}", output);
 
                 std::process::exit(1);
             }
         }
     }),
-    TestCase::new("test.regex", &|runner| {
-        spawn_and_wait(REGEX.clean(&runner.host_compiler.cargo, &runner.dirs));
+    TestCase::custom("test.regex", &|runner| {
+        REGEX.clean(&runner.dirs);
 
         // newer aho_corasick versions throw a deprecation warning
         let lint_rust_flags = format!("{} --cap-lints warn", runner.target_compiler.rustflags);
@@ -425,8 +221,8 @@ const fn new(config: &'static str, func: &'static dyn Fn(&TestRunner)) -> Self {
             spawn_and_wait(build_cmd);
         }
     }),
-    TestCase::new("test.portable-simd", &|runner| {
-        spawn_and_wait(PORTABLE_SIMD.clean(&runner.host_compiler.cargo, &runner.dirs));
+    TestCase::custom("test.portable-simd", &|runner| {
+        PORTABLE_SIMD.clean(&runner.dirs);
 
         let mut build_cmd = PORTABLE_SIMD.build(&runner.target_compiler, &runner.dirs);
         build_cmd.arg("--all-targets");
@@ -445,21 +241,22 @@ pub(crate) fn run_tests(
     channel: &str,
     sysroot_kind: SysrootKind,
     cg_clif_dylib: &Path,
-    host_triple: &str,
-    target_triple: &str,
+    bootstrap_host_compiler: &Compiler,
+    target_triple: 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(
+        let target_compiler = build_sysroot::build_sysroot(
             dirs,
             channel,
             SysrootKind::None,
             cg_clif_dylib,
-            &host_triple,
-            &target_triple,
+            bootstrap_host_compiler,
+            target_triple.clone(),
         );
 
+        let runner =
+            TestRunner::new(dirs.clone(), target_compiler, get_host_triple() == target_triple);
+
         BUILD_EXAMPLE_OUT_DIR.ensure_fresh(dirs);
         runner.run_testsuite(NO_SYSROOT_SUITE);
     } else {
@@ -470,26 +267,29 @@ pub(crate) fn run_tests(
     let run_extended_sysroot = config::get_bool("testsuite.extended_sysroot");
 
     if run_base_sysroot || run_extended_sysroot {
-        build_sysroot::build_sysroot(
+        let target_compiler = build_sysroot::build_sysroot(
             dirs,
             channel,
             sysroot_kind,
             cg_clif_dylib,
-            &host_triple,
-            &target_triple,
+            bootstrap_host_compiler,
+            target_triple.clone(),
         );
-    }
 
-    if run_base_sysroot {
-        runner.run_testsuite(BASE_SYSROOT_SUITE);
-    } else {
-        eprintln!("[SKIP] base_sysroot tests");
-    }
+        let runner =
+            TestRunner::new(dirs.clone(), target_compiler, get_host_triple() == target_triple);
 
-    if run_extended_sysroot {
-        runner.run_testsuite(EXTENDED_SYSROOT_SUITE);
-    } else {
-        eprintln!("[SKIP] extended_sysroot tests");
+        if run_base_sysroot {
+            runner.run_testsuite(BASE_SYSROOT_SUITE);
+        } else {
+            eprintln!("[SKIP] base_sysroot tests");
+        }
+
+        if run_extended_sysroot {
+            runner.run_testsuite(EXTENDED_SYSROOT_SUITE);
+        } else {
+            eprintln!("[SKIP] extended_sysroot tests");
+        }
     }
 }
 
@@ -497,84 +297,34 @@ struct TestRunner {
     is_native: bool,
     jit_supported: bool,
     dirs: Dirs,
-    host_compiler: Compiler,
     target_compiler: Compiler,
 }
 
 impl TestRunner {
-    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 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.
-                    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.
-                    runner = vec!["wine".to_owned()];
-                }
-                _ => {
-                    println!("Unknown non-native platform");
-                }
-            }
+    pub fn new(dirs: Dirs, mut target_compiler: Compiler, is_native: bool) -> Self {
+        if let Ok(rustflags) = env::var("RUSTFLAGS") {
+            target_compiler.rustflags.push(' ');
+            target_compiler.rustflags.push_str(&rustflags);
+        }
+        if let Ok(rustdocflags) = env::var("RUSTDOCFLAGS") {
+            target_compiler.rustdocflags.push(' ');
+            target_compiler.rustdocflags.push_str(&rustdocflags);
         }
 
         // FIXME fix `#[linkage = "extern_weak"]` without this
-        if target_triple.contains("darwin") {
-            rustflags = format!("{} -Clink-arg=-undefined -Clink-arg=dynamic_lookup", rustflags);
+        if target_compiler.triple.contains("darwin") {
+            target_compiler.rustflags.push_str(" -Clink-arg=-undefined -Clink-arg=dynamic_lookup");
         }
 
-        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 }
+        let jit_supported = is_native
+            && target_compiler.triple.contains("x86_64")
+            && !target_compiler.triple.contains("windows");
+
+        Self { is_native, jit_supported, dirs, target_compiler }
     }
 
     pub fn run_testsuite(&self, tests: &[TestCase]) {
-        for &TestCase { config, func } in tests {
+        for TestCase { config, cmd } in tests {
             let (tag, testname) = config.split_once('.').unwrap();
             let tag = tag.to_uppercase();
             let is_jit_test = tag == "JIT";
@@ -586,7 +336,47 @@ pub fn run_testsuite(&self, tests: &[TestCase]) {
                 eprintln!("[{tag}] {testname}");
             }
 
-            func(self);
+            match *cmd {
+                TestCaseCmd::Custom { func } => func(self),
+                TestCaseCmd::BuildLib { source, crate_types } => {
+                    self.run_rustc([source, "--crate-type", crate_types]);
+                }
+                TestCaseCmd::BuildBinAndRun { source, args } => {
+                    self.run_rustc([source]);
+                    self.run_out_command(
+                        source.split('/').last().unwrap().split('.').next().unwrap(),
+                        args,
+                    );
+                }
+                TestCaseCmd::JitBin { source, args } => {
+                    let mut jit_cmd = self.rustc_command([
+                        "-Zunstable-options",
+                        "-Cllvm-args=mode=jit",
+                        "-Cprefer-dynamic",
+                        source,
+                        "--cfg",
+                        "jit",
+                    ]);
+                    if !args.is_empty() {
+                        jit_cmd.env("CG_CLIF_JIT_ARGS", args);
+                    }
+                    spawn_and_wait(jit_cmd);
+
+                    eprintln!("[JIT-lazy] {testname}");
+                    let mut jit_cmd = self.rustc_command([
+                        "-Zunstable-options",
+                        "-Cllvm-args=mode=jit-lazy",
+                        "-Cprefer-dynamic",
+                        source,
+                        "--cfg",
+                        "jit",
+                    ]);
+                    if !args.is_empty() {
+                        jit_cmd.env("CG_CLIF_JIT_ARGS", args);
+                    }
+                    spawn_and_wait(jit_cmd);
+                }
+            }
         }
     }
 
@@ -603,6 +393,9 @@ fn rustc_command<I, S>(&self, args: I) -> Command
         cmd.arg("--out-dir");
         cmd.arg(format!("{}", BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).display()));
         cmd.arg("-Cdebuginfo=2");
+        cmd.arg("--target");
+        cmd.arg(&self.target_compiler.triple);
+        cmd.arg("-Cpanic=abort");
         cmd.args(args);
         cmd
     }
@@ -615,10 +408,7 @@ fn run_rustc<I, S>(&self, args: I)
         spawn_and_wait(self.rustc_command(args));
     }
 
-    fn run_out_command<'a, I>(&self, name: &str, args: I)
-    where
-        I: IntoIterator<Item = &'a str>,
-    {
+    fn run_out_command<'a>(&self, name: &str, args: &[&str]) {
         let mut full_cmd = vec![];
 
         // Prepend the RUN_WRAPPER's
@@ -630,7 +420,7 @@ fn run_out_command<'a, I>(&self, name: &str, args: I)
             BUILD_EXAMPLE_OUT_DIR.to_path(&self.dirs).join(name).to_str().unwrap().to_string(),
         );
 
-        for arg in args.into_iter() {
+        for arg in args {
             full_cmd.push(arg.to_string());
         }
 
diff --git a/compiler/rustc_codegen_cranelift/build_system/usage.txt b/compiler/rustc_codegen_cranelift/build_system/usage.txt
new file mode 100644 (file)
index 0000000..ab98ccc
--- /dev/null
@@ -0,0 +1,35 @@
+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]
+    ./y.rs abi-cafe [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features]
+    ./y.rs bench [--debug] [--sysroot none|clif|llvm] [--out-dir DIR] [--no-unstable-features]
+
+OPTIONS:
+    --debug
+            Build cg_clif and the standard library in debug mode rather than release mode.
+            Warning: An unoptimized cg_clif is very slow.
+
+    --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
+            Some features are not yet ready for production usage. This option will disable these
+            features. This includes the JIT mode and inline assembly support.
+
+REQUIREMENTS:
+    * Rustup: The build system has a hard coded dependency on rustup to install the right nightly
+      version and make sure it is used where necessary.
+    * Git: `./y.rs prepare` uses git for applying patches and on Windows for downloading test repos.
+    * Curl and tar (non-Windows only): Used by `./y.rs prepare` to download a single commit for
+      repos. Git will be used to clone the whole repo when using Windows.
+    * [Hyperfine](https://github.com/sharkdp/hyperfine/): Used for benchmarking with `./y.rs bench`.
index 2be70e8e421b2961e97b53c99f38c83256940365..da2a94a0a4ff84a3b307c22213e1813fd03ca55f 100644 (file)
@@ -1,12 +1,13 @@
 use std::env;
 use std::fs;
-use std::io::Write;
+use std::io::{self, Write};
 use std::path::{Path, PathBuf};
 use std::process::{self, Command, Stdio};
 
 use super::path::{Dirs, RelPath};
-use super::rustc_info::{get_cargo_path, get_host_triple, get_rustc_path, get_rustdoc_path};
+use super::rustc_info::{get_cargo_path, get_rustc_path, get_rustdoc_path};
 
+#[derive(Clone, Debug)]
 pub(crate) struct Compiler {
     pub(crate) cargo: PathBuf,
     pub(crate) rustc: PathBuf,
@@ -18,27 +19,47 @@ pub(crate) struct Compiler {
 }
 
 impl Compiler {
-    pub(crate) fn host() -> Compiler {
+    pub(crate) fn bootstrap_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: get_host_triple(),
+            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) fn set_cross_linker_and_runner(&mut self) {
+        match self.triple.as_str() {
+            "aarch64-unknown-linux-gnu" => {
+                // We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
+                self.rustflags += " -Clinker=aarch64-linux-gnu-gcc";
+                self.rustdocflags += " -Clinker=aarch64-linux-gnu-gcc";
+                self.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.
+                self.rustflags += " -Clinker=s390x-linux-gnu-gcc";
+                self.rustdocflags += " -Clinker=s390x-linux-gnu-gcc";
+                self.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.
+                self.runner = vec!["wine".to_owned()];
+            }
+            _ => {
+                println!("Unknown non-native platform");
+            }
         }
     }
 }
@@ -65,6 +86,7 @@ pub(crate) fn target_dir(&self, dirs: &Dirs) -> PathBuf {
         RelPath::BUILD.join(self.target).to_path(dirs)
     }
 
+    #[must_use]
     fn base_cmd(&self, command: &str, cargo: &Path, dirs: &Dirs) -> Command {
         let mut cmd = Command::new(cargo);
 
@@ -72,11 +94,13 @@ fn base_cmd(&self, command: &str, cargo: &Path, dirs: &Dirs) -> Command {
             .arg("--manifest-path")
             .arg(self.manifest_path(dirs))
             .arg("--target-dir")
-            .arg(self.target_dir(dirs));
+            .arg(self.target_dir(dirs))
+            .arg("--frozen");
 
         cmd
     }
 
+    #[must_use]
     fn build_cmd(&self, command: &str, compiler: &Compiler, dirs: &Dirs) -> Command {
         let mut cmd = self.base_cmd(command, &compiler.cargo, dirs);
 
@@ -105,9 +129,8 @@ pub(crate) fn fetch(&self, cargo: impl AsRef<Path>, dirs: &Dirs) -> Command {
         cmd
     }
 
-    #[must_use]
-    pub(crate) fn clean(&self, cargo: &Path, dirs: &Dirs) -> Command {
-        self.base_cmd("clean", cargo, dirs)
+    pub(crate) fn clean(&self, dirs: &Dirs) {
+        let _ = fs::remove_dir_all(self.target_dir(dirs));
     }
 
     #[must_use]
@@ -153,6 +176,23 @@ pub(crate) fn hyperfine_command(
     bench
 }
 
+#[must_use]
+pub(crate) fn git_command<'a>(repo_dir: impl Into<Option<&'a Path>>, cmd: &str) -> Command {
+    let mut git_cmd = Command::new("git");
+    git_cmd
+        .arg("-c")
+        .arg("user.name=Dummy")
+        .arg("-c")
+        .arg("user.email=dummy@example.com")
+        .arg("-c")
+        .arg("core.autocrlf=false")
+        .arg(cmd);
+    if let Some(repo_dir) = repo_dir.into() {
+        git_cmd.current_dir(repo_dir);
+    }
+    git_cmd
+}
+
 #[track_caller]
 pub(crate) fn try_hard_link(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
     let src = src.as_ref();
@@ -169,6 +209,22 @@ pub(crate) fn spawn_and_wait(mut cmd: Command) {
     }
 }
 
+// Based on the retry function in rust's src/ci/shared.sh
+#[track_caller]
+pub(crate) fn retry_spawn_and_wait(tries: u64, mut cmd: Command) {
+    for i in 1..tries + 1 {
+        if i != 1 {
+            println!("Command failed. Attempt {i}/{tries}:");
+        }
+        if cmd.spawn().unwrap().wait().unwrap().success() {
+            return;
+        }
+        std::thread::sleep(std::time::Duration::from_secs(i * 5));
+    }
+    println!("The command has failed after {tries} attempts.");
+    process::exit(1);
+}
+
 #[track_caller]
 pub(crate) fn spawn_and_wait_with_input(mut cmd: Command, input: String) -> String {
     let mut child = cmd
@@ -190,6 +246,14 @@ pub(crate) fn spawn_and_wait_with_input(mut cmd: Command, input: String) -> Stri
     String::from_utf8(output.stdout).unwrap()
 }
 
+pub(crate) fn remove_dir_if_exists(path: &Path) {
+    match fs::remove_dir_all(&path) {
+        Ok(()) => {}
+        Err(err) if err.kind() == io::ErrorKind::NotFound => {}
+        Err(err) => panic!("Failed to remove {path}: {err}", path = path.display()),
+    }
+}
+
 pub(crate) fn copy_dir_recursively(from: &Path, to: &Path) {
     for entry in fs::read_dir(from).unwrap() {
         let entry = entry.unwrap();
index 1760e5836ecce00a48f7a0236748dfb94329fce0..cdfc2e143e6748247d056e11488b5adae5ea21f7 100755 (executable)
@@ -1,10 +1,9 @@
 #!/usr/bin/env bash
 set -e
 
-rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version}
-rm -rf target/ build/ dist/ perf.data{,.old} y.bin
-rm -rf download/
+rm -rf target/ download/ build/ dist/ y.bin y.bin.dSYM y.exe y.pdb
 
 # Kept for now in case someone updates their checkout of cg_clif before running clean_all.sh
 # FIXME remove at some point in the future
 rm -rf rand/ regex/ simple-raytracer/ portable-simd/ abi-checker/ abi-cafe/
+rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version}
index 258b67e931476850a25cab17bbc2c3300a243821..d49cc90791a5d5fb01a81bbf7aeb905405681d55 100644 (file)
@@ -44,10 +44,8 @@ aot.issue-72793
 
 testsuite.extended_sysroot
 test.rust-random/rand
-bench.simple-raytracer
+test.simple-raytracer
 test.libcore
 test.regex-shootout-regex-dna
 test.regex
 test.portable-simd
-
-testsuite.abi-cafe
diff --git a/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch
deleted file mode 100644 (file)
index 89e2b61..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-From b742f03694b920cc14400727d54424e8e1b60928 Mon Sep 17 00:00:00 2001
-From: bjorn3 <bjorn3@users.noreply.github.com>
-Date: Thu, 18 Nov 2021 19:28:40 +0100
-Subject: [PATCH] Disable unsupported tests
-
----
- crates/core_simd/src/elements/int.rs     | 8 ++++++++
- crates/core_simd/src/elements/uint.rs    | 4 ++++
- crates/core_simd/src/masks/full_masks.rs | 6 ++++++
- crates/core_simd/src/vector.rs           | 2 ++
- crates/core_simd/tests/masks.rs          | 3 ---
- 5 files changed, 20 insertions(+), 3 deletions(-)
-
-diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs
-index e8e8f68..7173c24 100644
---- a/crates/core_simd/src/vector.rs
-+++ b/crates/core_simd/src/vector.rs
-@@ -250,6 +250,7 @@ where
-         unsafe { intrinsics::simd_cast(self) }
-     }
-+    /*
-     /// Reads from potentially discontiguous indices in `slice` to construct a SIMD vector.
-     /// If an index is out-of-bounds, the lane is instead selected from the `or` vector.
-     ///
-@@ -473,6 +474,7 @@ where
-             // Cleared ☢️ *mut T Zone
-         }
-     }
-+    */
- }
- impl<T, const LANES: usize> Copy for Simd<T, LANES>
--- 
-2.25.1
index 8d9ee3f25c49db03b35c65208fe8fc6740c63b63..865aa833a5eef4c01754916a1534d54c84ec175f 100644 (file)
@@ -18,7 +18,7 @@ new file mode 100644
 index 0000000..46fd999
 --- /dev/null
 +++ b/library/core/tests/Cargo.toml
-@@ -0,0 +1,11 @@
+@@ -0,0 +1,12 @@
 +[package]
 +name = "core"
 +version = "0.0.0"
@@ -29,6 +29,7 @@ index 0000000..46fd999
 +path = "lib.rs"
 +
 +[dependencies]
-+rand = "0.7"
++rand = { version = "0.8.5", default-features = false }
++rand_xorshift = { version = "0.3.0", default-features = false }
 --
 2.21.0 (Apple Git-122)
index d8f28dbcc15c8c43d9631834b087f34ed547cebb..77345b9a17c6edca7102326001fcef783e74a1c9 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-12-13"
+channel = "nightly-2023-01-20"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
index 9362b47fa6d83137701069fc9c9aced1a9b0ab22..c993430b830b6ebe3d4c1fc919f50fd043f57311 100644 (file)
@@ -26,7 +26,7 @@ fn main() {
     env::set_var("RUSTDOCFLAGS", env::var("RUSTDOCFLAGS").unwrap_or(String::new()) + &rustflags);
 
     // Ensure that the right toolchain is used
-    env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN"));
+    env::set_var("RUSTUP_TOOLCHAIN", env!("TOOLCHAIN_NAME"));
 
     let args: Vec<_> = match env::args().nth(1).as_deref() {
         Some("jit") => {
index 3abfcd8ddc824e493c5f3a3f4086c6a9b4c989f4..c187f54a60e775a0b2a5bca42406390035f6310d 100644 (file)
@@ -24,7 +24,7 @@ fn main() {
     }
 
     // Ensure that the right toolchain is used
-    env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN"));
+    env::set_var("RUSTUP_TOOLCHAIN", env!("TOOLCHAIN_NAME"));
 
     #[cfg(unix)]
     Command::new("rustc").args(args).exec();
index a19d72acfa83e037ac857e1719c3ca1a988895f9..a6528ac41aee08f9f57ae4e396af40c99b239728 100644 (file)
@@ -24,7 +24,7 @@ fn main() {
     }
 
     // Ensure that the right toolchain is used
-    env::set_var("RUSTUP_TOOLCHAIN", env!("RUSTUP_TOOLCHAIN"));
+    env::set_var("RUSTUP_TOOLCHAIN", env!("TOOLCHAIN_NAME"));
 
     #[cfg(unix)]
     Command::new("rustdoc").args(args).exec();
index bc4c06ed7d2988e6d28810d11ead10c7c8d05022..34e3981b5381f5ceeb7e5df8d6a4f6d94ee87b06 100755 (executable)
@@ -17,10 +17,10 @@ case $1 in
         done
 
         ./clean_all.sh
-        ./y.rs prepare
 
-        (cd build_sysroot && cargo update)
+        ./y.rs prepare
 
+        (cd download/sysroot && cargo update && cargo fetch && cp Cargo.lock ../../build_sysroot/)
         ;;
     "commit")
         git add rust-toolchain build_sysroot/Cargo.lock
index 6c64b7de7daa10d863a903a186e0ee9c4846aeed..a08e80dd19abc74bf93036d1707059325464b86e 100644 (file)
@@ -10,7 +10,7 @@ git fetch
 git checkout -- .
 git checkout "$(rustc -V | cut -d' ' -f3 | tr -d '(')"
 
-git am ../patches/*-sysroot-*.patch
+git -c user.name=Dummy -c user.email=dummy@example.com am ../patches/*-sysroot-*.patch
 
 git apply - <<EOF
 diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
@@ -25,8 +25,8 @@ index d95b5b7f17f..00b6f0e3635 100644
 +compiler_builtins = { version = "0.1.66", features = ['rustc-dep-of-std', 'no-asm'] }
 
  [dev-dependencies]
- rand = "0.7"
- rand_xorshift = "0.2"
+ rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
+ rand_xorshift = "0.3.0"
 EOF
 
 cat > config.toml <<EOF
@@ -51,7 +51,7 @@ 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)"
+export CFG_VIRTUAL_RUST_SOURCE_BASE_DIR="$(cd download/sysroot/sysroot_src; pwd)"
 
 # Allow the testsuite to use llvm tools
 host_triple=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
index 12ecb8cf4e17d6473d36610183c6e5224d196db9..07c9ae6ee9ff2c1f4340ac0ead9c68879f82ba4e 100755 (executable)
@@ -11,7 +11,7 @@ pushd rust
 command -v rg >/dev/null 2>&1 || cargo install ripgrep
 
 rm -r tests/ui/{extern/,unsized-locals/,lto/,linkage*} || true
-for test in $(rg --files-with-matches "lto|// needs-asm-support|// needs-unwind" tests/{ui,incremental}); do
+for test in $(rg --files-with-matches "lto|// needs-asm-support|// needs-unwind" tests/{codegen-units,ui,incremental}); do
   rm $test
 done
 
@@ -32,20 +32,13 @@ rm tests/incremental/issue-80691-bad-eval-cache.rs # -Cpanic=abort causes abort
 # requires compiling with -Cpanic=unwind
 rm -r tests/ui/macros/rfc-2011-nicer-assert-messages/
 rm -r tests/run-make/test-benches
+rm tests/ui/test-attrs/test-type.rs
 
 # vendor intrinsics
 rm tests/ui/sse2.rs # cpuid not supported, so sse2 not detected
 rm tests/ui/intrinsics/const-eval-select-x86_64.rs # requires x86_64 vendor intrinsics
 rm tests/ui/simd/array-type.rs # "Index argument for `simd_insert` is not a constant"
-rm tests/ui/simd/intrinsic/generic-bitmask-pass.rs # simd_bitmask unimplemented
-rm tests/ui/simd/intrinsic/generic-as.rs # simd_as unimplemented
-rm tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs # simd_saturating_add unimplemented
 rm tests/ui/simd/intrinsic/float-math-pass.rs # simd_fcos unimplemented
-rm tests/ui/simd/intrinsic/generic-gather-pass.rs # simd_gather unimplemented
-rm tests/ui/simd/intrinsic/generic-select-pass.rs # simd_select_bitmask unimplemented
-rm tests/ui/simd/issue-85915-simd-ptrs.rs # simd_gather unimplemented
-rm tests/ui/simd/issue-89193.rs # simd_gather unimplemented
-rm tests/ui/simd/simd-bitmask.rs # simd_bitmask unimplemented
 
 # exotic linkages
 rm tests/ui/issues/issue-33992.rs # unsupported linkages
@@ -64,10 +57,7 @@ rm tests/ui/intrinsics/intrinsic-nearby.rs # unimplemented nearbyintf32 and near
 rm tests/ui/target-feature/missing-plusminus.rs # error not implemented
 rm tests/ui/fn/dyn-fn-alignment.rs # wants a 256 byte alignment
 rm -r tests/run-make/emit-named-files # requires full --emit support
-rm tests/ui/abi/stack-probes.rs # stack probes not yet implemented
-rm tests/ui/simd/intrinsic/ptr-cast.rs # simd_expose_addr intrinsic unimplemented
 rm -r tests/run-make/repr128-dwarf # debuginfo test
-rm tests/codegen-units/item-collection/asm-sym.rs # requires support for sym in asm!()
 
 # optimization tests
 # ==================
@@ -88,6 +78,20 @@ rm tests/ui/mir/mir_raw_fat_ptr.rs # same
 rm tests/ui/consts/issue-33537.rs # same
 rm tests/ui/layout/valid_range_oob.rs # different ICE message
 
+rm tests/ui/consts/issue-miri-1910.rs # different error message
+rm tests/ui/consts/offset_ub.rs # same
+rm tests/ui/intrinsics/panic-uninitialized-zeroed.rs # same
+rm tests/ui/lint/lint-const-item-mutation.rs # same
+rm tests/ui/pattern/usefulness/doc-hidden-non-exhaustive.rs # same
+rm tests/ui/suggestions/derive-trait-for-method-call.rs # same
+rm tests/ui/typeck/issue-46112.rs # same
+
+rm tests/ui/proc-macro/crt-static.rs # extra warning about -Cpanic=abort for proc macros
+rm tests/ui/proc-macro/proc-macro-deprecated-attr.rs # same
+rm tests/ui/proc-macro/quote-debug.rs # same
+rm tests/ui/proc-macro/no-missing-docs.rs # same
+rm tests/ui/rust-2018/proc-macro-crate-in-paths.rs # same
+
 # 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
 # ============================================================
@@ -102,23 +106,20 @@ rm -r tests/ui/consts/missing_span_in_backtrace.rs # expects sysroot source to b
 # ============
 rm tests/incremental/spike-neg1.rs # errors out for some reason
 rm tests/incremental/spike-neg2.rs # same
-rm tests/ui/issues/issue-74564-if-expr-stack-overflow.rs # gives a stackoverflow before the backend runs
-rm tests/ui/mir/ssa-analysis-regression-50041.rs # produces ICE
-rm tests/ui/type-alias-impl-trait/assoc-projection-ice.rs # produces ICE
 
 rm tests/ui/simd/intrinsic/generic-reduction-pass.rs # simd_reduce_add_unordered doesn't accept an accumulator for integer vectors
 
-rm tests/ui/runtime/out-of-stack.rs # SIGSEGV instead of SIGABRT for some reason (#1301)
+rm tests/ui/simd/intrinsic/generic-as.rs # crash when accessing vector type filed (#1318)
+rm tests/ui/simd/simd-bitmask.rs # crash
+
+rm tests/ui/dyn-star/dyn-star-to-dyn.rs
+rm tests/ui/dyn-star/dispatch-on-pin-mut.rs
 
 # bugs in the test suite
 # ======================
 rm tests/ui/backtrace.rs # TODO warning
 rm tests/ui/simple_global_asm.rs # TODO add needs-asm-support
-rm tests/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 tests/run-make/native-link-modifier-bundle
 rm tests/ui/process/nofile-limit.rs # TODO some AArch64 linking issue
-rm tests/ui/dyn-star/dispatch-on-pin-mut.rs # TODO failed assertion in vtable::get_ptr_and_method_ref
 
 rm tests/ui/stdio-is-blocking.rs # really slow with unoptimized libstd
 
index 65cc6b4376713d8c7e855c2fca1f833894a3cd09..3c34585d4191e6ef1eaa80b82dd06dc578972e9a 100644 (file)
@@ -7,6 +7,7 @@
 use cranelift_module::ModuleError;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::ty::layout::FnAbiOf;
+use rustc_session::Session;
 use rustc_target::abi::call::{Conv, FnAbi};
 use rustc_target::spec::abi::Abi;
 
@@ -22,7 +23,7 @@ fn clif_sig_from_fn_abi<'tcx>(
     default_call_conv: CallConv,
     fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
 ) -> Signature {
-    let call_conv = conv_to_call_conv(fn_abi.conv, default_call_conv);
+    let call_conv = conv_to_call_conv(tcx.sess, fn_abi.conv, default_call_conv);
 
     let inputs = fn_abi.args.iter().map(|arg_abi| arg_abi.get_abi_param(tcx).into_iter()).flatten();
 
@@ -33,24 +34,32 @@ fn clif_sig_from_fn_abi<'tcx>(
     Signature { params, returns, call_conv }
 }
 
-pub(crate) fn conv_to_call_conv(c: Conv, default_call_conv: CallConv) -> CallConv {
+pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: CallConv) -> CallConv {
     match c {
         Conv::Rust | Conv::C => default_call_conv,
         Conv::RustCold => CallConv::Cold,
         Conv::X86_64SysV => CallConv::SystemV,
         Conv::X86_64Win64 => CallConv::WindowsFastcall,
-        Conv::ArmAapcs
-        | Conv::CCmseNonSecureCall
-        | Conv::Msp430Intr
+
+        // Should already get a back compat warning
+        Conv::X86Fastcall | Conv::X86Stdcall | Conv::X86ThisCall | Conv::X86VectorCall => {
+            default_call_conv
+        }
+
+        Conv::X86Intr => sess.fatal("x86-interrupt call conv not yet implemented"),
+
+        Conv::ArmAapcs => sess.fatal("aapcs call conv not yet implemented"),
+        Conv::CCmseNonSecureCall => {
+            sess.fatal("C-cmse-nonsecure-call call conv is not yet implemented");
+        }
+
+        Conv::Msp430Intr
         | Conv::PtxKernel
-        | Conv::X86Fastcall
-        | Conv::X86Intr
-        | Conv::X86Stdcall
-        | Conv::X86ThisCall
-        | Conv::X86VectorCall
         | Conv::AmdGpuKernel
         | Conv::AvrInterrupt
-        | Conv::AvrNonBlockingInterrupt => todo!("{:?}", c),
+        | Conv::AvrNonBlockingInterrupt => {
+            unreachable!("tried to use {c:?} call conv which only exists on an unsupported target");
+        }
     }
 }
 
@@ -161,6 +170,12 @@ fn make_local_place<'tcx>(
     layout: TyAndLayout<'tcx>,
     is_ssa: bool,
 ) -> CPlace<'tcx> {
+    if layout.is_unsized() {
+        fx.tcx.sess.span_fatal(
+            fx.mir.local_decls[local].source_info.span,
+            "unsized locals are not yet supported",
+        );
+    }
     let place = if is_ssa {
         if let rustc_target::abi::Abi::ScalarPair(_, _) = layout.abi {
             CPlace::new_var_pair(fx, local, layout)
index 89d955e8bf2e1d84c1a40045d0b063140d325525..d3a8c10657e8d5cdb78f40fdc10695d7685e9c50 100644 (file)
@@ -113,6 +113,8 @@ pub(crate) fn codegen_fn<'tcx>(
     };
 
     tcx.sess.time("codegen clif ir", || codegen_fn_body(&mut fx, start_block));
+    fx.bcx.seal_all_blocks();
+    fx.bcx.finalize();
 
     // Recover all necessary data from fx, before accessing func will prevent future access to it.
     let symbol_name = fx.symbol_name;
@@ -303,6 +305,9 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
         let source_info = bb_data.terminator().source_info;
         fx.set_debug_loc(source_info);
 
+        let _print_guard =
+            crate::PrintOnPanic(|| format!("terminator {:?}", bb_data.terminator().kind));
+
         match &bb_data.terminator().kind {
             TerminatorKind::Goto { target } => {
                 if let TerminatorKind::Return = fx.mir[*target].terminator().kind {
@@ -464,7 +469,10 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
                     *destination,
                 );
             }
-            TerminatorKind::Resume | TerminatorKind::Abort => {
+            TerminatorKind::Abort => {
+                codegen_panic_cannot_unwind(fx, source_info);
+            }
+            TerminatorKind::Resume => {
                 // FIXME implement unwinding
                 fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
             }
@@ -487,9 +495,6 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
             }
         };
     }
-
-    fx.bcx.seal_all_blocks();
-    fx.bcx.finalize();
 }
 
 fn codegen_stmt<'tcx>(
@@ -932,7 +937,28 @@ pub(crate) fn codegen_panic<'tcx>(
     codegen_panic_inner(fx, rustc_hir::LangItem::Panic, &args, source_info.span);
 }
 
-pub(crate) fn codegen_panic_inner<'tcx>(
+pub(crate) fn codegen_panic_nounwind<'tcx>(
+    fx: &mut FunctionCx<'_, '_, 'tcx>,
+    msg_str: &str,
+    source_info: mir::SourceInfo,
+) {
+    let msg_ptr = fx.anonymous_str(msg_str);
+    let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap());
+    let args = [msg_ptr, msg_len];
+
+    codegen_panic_inner(fx, rustc_hir::LangItem::PanicNounwind, &args, source_info.span);
+}
+
+pub(crate) fn codegen_panic_cannot_unwind<'tcx>(
+    fx: &mut FunctionCx<'_, '_, 'tcx>,
+    source_info: mir::SourceInfo,
+) {
+    let args = [];
+
+    codegen_panic_inner(fx, rustc_hir::LangItem::PanicCannotUnwind, &args, source_info.span);
+}
+
+fn codegen_panic_inner<'tcx>(
     fx: &mut FunctionCx<'_, '_, 'tcx>,
     lang_item: rustc_hir::LangItem,
     args: &[Value],
@@ -949,11 +975,7 @@ pub(crate) fn codegen_panic_inner<'tcx>(
 
     fx.lib_call(
         &*symbol_name,
-        vec![
-            AbiParam::new(fx.pointer_type),
-            AbiParam::new(fx.pointer_type),
-            AbiParam::new(fx.pointer_type),
-        ],
+        args.iter().map(|&arg| AbiParam::new(fx.bcx.func.dfg.value_type(arg))).collect(),
         vec![],
         args,
     );
index 2dcd42fbd8f431833ac46b414c539e40c828f0e8..f41af3a9e636631949be8a616b799a3dfc6644c8 100644 (file)
@@ -35,7 +35,8 @@ pub(crate) fn scalar_to_clif_type(tcx: TyCtxt<'_>, scalar: Scalar) -> Type {
         },
         Primitive::F32 => types::F32,
         Primitive::F64 => types::F64,
-        Primitive::Pointer => pointer_ty(tcx),
+        // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
+        Primitive::Pointer(_) => pointer_ty(tcx),
     }
 }
 
@@ -167,6 +168,15 @@ pub(crate) fn codegen_icmp_imm(
     }
 }
 
+pub(crate) fn codegen_bitcast(fx: &mut FunctionCx<'_, '_, '_>, dst_ty: Type, val: Value) -> Value {
+    let mut flags = MemFlags::new();
+    flags.set_endianness(match fx.tcx.data_layout.endian {
+        rustc_target::abi::Endian::Big => cranelift_codegen::ir::Endianness::Big,
+        rustc_target::abi::Endian::Little => cranelift_codegen::ir::Endianness::Little,
+    });
+    fx.bcx.ins().bitcast(dst_ty, flags, val)
+}
+
 pub(crate) fn type_zero_value(bcx: &mut FunctionBuilder<'_>, ty: Type) -> Value {
     if ty == types::I128 {
         let zero = bcx.ins().iconst(types::I64, 0);
diff --git a/compiler/rustc_codegen_cranelift/src/cranelift_native.rs b/compiler/rustc_codegen_cranelift/src/cranelift_native.rs
new file mode 100644 (file)
index 0000000..6c4efca
--- /dev/null
@@ -0,0 +1,248 @@
+// Vendored from https://github.com/bytecodealliance/wasmtime/blob/b58a197d33f044193c3d608010f5e6ec394ac07e/cranelift/native/src/lib.rs
+// which is licensed as
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+// unlike rustc_codegen_cranelift itself. Also applies a small change to remove #![cfg_attr] that
+// rust's CI complains about and to fix formatting to match rustc.
+// FIXME revert back to the external crate with Cranelift 0.93
+#![allow(warnings)]
+
+//! Performs autodetection of the host for the purposes of running
+//! Cranelift to generate code to run on the same machine.
+
+#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates, unstable_features)]
+#![warn(unused_import_braces)]
+
+use cranelift_codegen::isa;
+use target_lexicon::Triple;
+
+/// Return an `isa` builder configured for the current host
+/// machine, or `Err(())` if the host machine is not supported
+/// in the current configuration.
+pub fn builder() -> Result<isa::Builder, &'static str> {
+    builder_with_options(true)
+}
+
+/// Return an `isa` builder configured for the current host
+/// machine, or `Err(())` if the host machine is not supported
+/// in the current configuration.
+///
+/// Selects the given backend variant specifically; this is
+/// useful when more than oen backend exists for a given target
+/// (e.g., on x86-64).
+pub fn builder_with_options(infer_native_flags: bool) -> Result<isa::Builder, &'static str> {
+    let mut isa_builder = isa::lookup(Triple::host()).map_err(|err| match err {
+        isa::LookupError::SupportDisabled => "support for architecture disabled at compile time",
+        isa::LookupError::Unsupported => "unsupported architecture",
+    })?;
+
+    #[cfg(target_arch = "x86_64")]
+    {
+        use cranelift_codegen::settings::Configurable;
+
+        if !std::is_x86_feature_detected!("sse2") {
+            return Err("x86 support requires SSE2");
+        }
+
+        if !infer_native_flags {
+            return Ok(isa_builder);
+        }
+
+        // These are temporarily enabled by default (see #3810 for
+        // more) so that a default-constructed `Flags` can work with
+        // default Wasmtime features. Otherwise, the user must
+        // explicitly use native flags or turn these on when on x86-64
+        // platforms to avoid a configuration panic. In order for the
+        // "enable if detected" logic below to work, we must turn them
+        // *off* (differing from the default) and then re-enable below
+        // if present.
+        isa_builder.set("has_sse3", "false").unwrap();
+        isa_builder.set("has_ssse3", "false").unwrap();
+        isa_builder.set("has_sse41", "false").unwrap();
+        isa_builder.set("has_sse42", "false").unwrap();
+
+        if std::is_x86_feature_detected!("sse3") {
+            isa_builder.enable("has_sse3").unwrap();
+        }
+        if std::is_x86_feature_detected!("ssse3") {
+            isa_builder.enable("has_ssse3").unwrap();
+        }
+        if std::is_x86_feature_detected!("sse4.1") {
+            isa_builder.enable("has_sse41").unwrap();
+        }
+        if std::is_x86_feature_detected!("sse4.2") {
+            isa_builder.enable("has_sse42").unwrap();
+        }
+        if std::is_x86_feature_detected!("popcnt") {
+            isa_builder.enable("has_popcnt").unwrap();
+        }
+        if std::is_x86_feature_detected!("avx") {
+            isa_builder.enable("has_avx").unwrap();
+        }
+        if std::is_x86_feature_detected!("avx2") {
+            isa_builder.enable("has_avx2").unwrap();
+        }
+        if std::is_x86_feature_detected!("fma") {
+            isa_builder.enable("has_fma").unwrap();
+        }
+        if std::is_x86_feature_detected!("bmi1") {
+            isa_builder.enable("has_bmi1").unwrap();
+        }
+        if std::is_x86_feature_detected!("bmi2") {
+            isa_builder.enable("has_bmi2").unwrap();
+        }
+        if std::is_x86_feature_detected!("avx512bitalg") {
+            isa_builder.enable("has_avx512bitalg").unwrap();
+        }
+        if std::is_x86_feature_detected!("avx512dq") {
+            isa_builder.enable("has_avx512dq").unwrap();
+        }
+        if std::is_x86_feature_detected!("avx512f") {
+            isa_builder.enable("has_avx512f").unwrap();
+        }
+        if std::is_x86_feature_detected!("avx512vl") {
+            isa_builder.enable("has_avx512vl").unwrap();
+        }
+        if std::is_x86_feature_detected!("avx512vbmi") {
+            isa_builder.enable("has_avx512vbmi").unwrap();
+        }
+        if std::is_x86_feature_detected!("lzcnt") {
+            isa_builder.enable("has_lzcnt").unwrap();
+        }
+    }
+
+    #[cfg(target_arch = "aarch64")]
+    {
+        use cranelift_codegen::settings::Configurable;
+
+        if !infer_native_flags {
+            return Ok(isa_builder);
+        }
+
+        if std::arch::is_aarch64_feature_detected!("lse") {
+            isa_builder.enable("has_lse").unwrap();
+        }
+
+        if std::arch::is_aarch64_feature_detected!("paca") {
+            isa_builder.enable("has_pauth").unwrap();
+        }
+
+        if cfg!(target_os = "macos") {
+            // Pointer authentication is always available on Apple Silicon.
+            isa_builder.enable("sign_return_address").unwrap();
+            // macOS enforces the use of the B key for return addresses.
+            isa_builder.enable("sign_return_address_with_bkey").unwrap();
+        }
+    }
+
+    // There is no is_s390x_feature_detected macro yet, so for now
+    // we use getauxval from the libc crate directly.
+    #[cfg(all(target_arch = "s390x", target_os = "linux"))]
+    {
+        use cranelift_codegen::settings::Configurable;
+
+        if !infer_native_flags {
+            return Ok(isa_builder);
+        }
+
+        let v = unsafe { libc::getauxval(libc::AT_HWCAP) };
+        const HWCAP_S390X_VXRS_EXT2: libc::c_ulong = 32768;
+        if (v & HWCAP_S390X_VXRS_EXT2) != 0 {
+            isa_builder.enable("has_vxrs_ext2").unwrap();
+            // There is no separate HWCAP bit for mie2, so assume
+            // that any machine with vxrs_ext2 also has mie2.
+            isa_builder.enable("has_mie2").unwrap();
+        }
+    }
+
+    // `is_riscv_feature_detected` is nightly only for now, use
+    // getauxval from the libc crate directly as a temporary measure.
+    #[cfg(all(target_arch = "riscv64", target_os = "linux"))]
+    {
+        use cranelift_codegen::settings::Configurable;
+
+        if !infer_native_flags {
+            return Ok(isa_builder);
+        }
+
+        let v = unsafe { libc::getauxval(libc::AT_HWCAP) };
+
+        const HWCAP_RISCV_EXT_A: libc::c_ulong = 1 << (b'a' - b'a');
+        const HWCAP_RISCV_EXT_C: libc::c_ulong = 1 << (b'c' - b'a');
+        const HWCAP_RISCV_EXT_D: libc::c_ulong = 1 << (b'd' - b'a');
+        const HWCAP_RISCV_EXT_F: libc::c_ulong = 1 << (b'f' - b'a');
+        const HWCAP_RISCV_EXT_M: libc::c_ulong = 1 << (b'm' - b'a');
+        const HWCAP_RISCV_EXT_V: libc::c_ulong = 1 << (b'v' - b'a');
+
+        if (v & HWCAP_RISCV_EXT_A) != 0 {
+            isa_builder.enable("has_a").unwrap();
+        }
+
+        if (v & HWCAP_RISCV_EXT_C) != 0 {
+            isa_builder.enable("has_c").unwrap();
+        }
+
+        if (v & HWCAP_RISCV_EXT_D) != 0 {
+            isa_builder.enable("has_d").unwrap();
+        }
+
+        if (v & HWCAP_RISCV_EXT_F) != 0 {
+            isa_builder.enable("has_f").unwrap();
+
+            // TODO: There doesn't seem to be a bit associated with this extension
+            // rust enables it with the `f` extension:
+            // https://github.com/rust-lang/stdarch/blob/790411f93c4b5eada3c23abb4c9a063fb0b24d99/crates/std_detect/src/detect/os/linux/riscv.rs#L43
+            isa_builder.enable("has_zicsr").unwrap();
+        }
+
+        if (v & HWCAP_RISCV_EXT_M) != 0 {
+            isa_builder.enable("has_m").unwrap();
+        }
+
+        if (v & HWCAP_RISCV_EXT_V) != 0 {
+            isa_builder.enable("has_v").unwrap();
+        }
+
+        // TODO: ZiFencei does not have a bit associated with it
+        // TODO: Zbkb does not have a bit associated with it
+    }
+
+    // squelch warnings about unused mut/variables on some platforms.
+    drop(&mut isa_builder);
+    drop(infer_native_flags);
+
+    Ok(isa_builder)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::builder;
+    use cranelift_codegen::isa::CallConv;
+    use cranelift_codegen::settings;
+
+    #[test]
+    fn test() {
+        if let Ok(isa_builder) = builder() {
+            let flag_builder = settings::builder();
+            let isa = isa_builder.finish(settings::Flags::new(flag_builder)).unwrap();
+
+            if cfg!(all(target_os = "macos", target_arch = "aarch64")) {
+                assert_eq!(isa.default_call_conv(), CallConv::AppleAarch64);
+            } else if cfg!(any(unix, target_os = "nebulet")) {
+                assert_eq!(isa.default_call_conv(), CallConv::SystemV);
+            } else if cfg!(windows) {
+                assert_eq!(isa.default_call_conv(), CallConv::WindowsFastcall);
+            }
+
+            if cfg!(target_pointer_width = "64") {
+                assert_eq!(isa.pointer_bits(), 64);
+            } else if cfg!(target_pointer_width = "32") {
+                assert_eq!(isa.pointer_bits(), 32);
+            } else if cfg!(target_pointer_width = "16") {
+                assert_eq!(isa.pointer_bits(), 16);
+            }
+        }
+    }
+}
+
+/// Version number of this crate.
+pub const VERSION: &str = env!("CARGO_PKG_VERSION");
index 28fbcb15b2b5893ab9ea6912d5047a05a6f293a7..3a7421d8b30d843354e3462d1fec296a7f957035 100644 (file)
 pub(crate) use emit::{DebugReloc, DebugRelocName};
 pub(crate) use unwind::UnwindContext;
 
+pub(crate) fn producer() -> String {
+    format!(
+        "cg_clif (rustc {}, cranelift {})",
+        rustc_interface::util::rustc_version_str().unwrap_or("unknown version"),
+        cranelift_codegen::VERSION,
+    )
+}
+
 pub(crate) struct DebugContext {
     endian: RunTimeEndian,
 
@@ -57,11 +65,7 @@ pub(crate) fn new(tcx: TyCtxt<'_>, isa: &dyn TargetIsa) -> Self {
 
         let mut dwarf = DwarfUnit::new(encoding);
 
-        let producer = format!(
-            "cg_clif (rustc {}, cranelift {})",
-            rustc_interface::util::rustc_version_str().unwrap_or("unknown version"),
-            cranelift_codegen::VERSION,
-        );
+        let producer = producer();
         let comp_dir = tcx
             .sess
             .opts
index f873561c1713f37853821e3548ad6511a7981f58..d4494a9e45de49981df3dcf679809e225132d054 100644 (file)
@@ -108,6 +108,8 @@ pub(crate) fn join(
 
         self.concurrency_limiter.finished();
 
+        sess.abort_if_errors();
+
         (
             CodegenResults {
                 modules,
@@ -169,10 +171,22 @@ fn emit_cgu(
 fn emit_module(
     output_filenames: &OutputFilenames,
     prof: &SelfProfilerRef,
-    object: cranelift_object::object::write::Object<'_>,
+    mut object: cranelift_object::object::write::Object<'_>,
     kind: ModuleKind,
     name: String,
 ) -> Result<CompiledModule, String> {
+    if object.format() == cranelift_object::object::BinaryFormat::Elf {
+        let comment_section = object.add_section(
+            Vec::new(),
+            b".comment".to_vec(),
+            cranelift_object::object::SectionKind::OtherString,
+        );
+        let mut producer = vec![0];
+        producer.extend(crate::debuginfo::producer().as_bytes());
+        producer.push(0);
+        object.set_section_data(comment_section, producer, 1);
+    }
+
     let tmp_file = output_filenames.temp_path(OutputType::Object, Some(&name));
     let mut file = match File::create(&tmp_file) {
         Ok(file) => file,
@@ -399,8 +413,6 @@ pub(crate) fn run_aot(
             .collect::<Vec<_>>()
     });
 
-    tcx.sess.abort_if_errors();
-
     let mut allocator_module = make_module(tcx.sess, &backend_config, "allocator_shim".to_string());
     let mut allocator_unwind_context = UnwindContext::new(allocator_module.isa(), true);
     let created_alloc_shim =
index 7bc161fbe55236a1b03ad08db5a80e274f94d7f8..d2ae6978ca2a8ee84e63410dd0d6d6aa1985461b 100644 (file)
@@ -33,8 +33,8 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
 
                 // 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),
+                    types::F32 => codegen_bitcast(fx, types::I32, a_lane),
+                    types::F64 => codegen_bitcast(fx, types::I64, a_lane),
                     _ => a_lane,
                 };
 
index e4ac89a7bec6b245d17cf41828f392a76df8e4dc..d561cf139b6c9bca3ac97f0d985f006383916322 100644 (file)
@@ -21,6 +21,7 @@ macro_rules! intrinsic_args {
 pub(crate) use cpuid::codegen_cpuid_call;
 pub(crate) use llvm::codegen_llvm_intrinsic_call;
 
+use rustc_middle::ty::layout::HasParamEnv;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_span::symbol::{kw, sym, Symbol};
@@ -200,7 +201,7 @@ fn bool_to_zero_or_max_uint<'tcx>(
     let mut res = fx.bcx.ins().bmask(int_ty, val);
 
     if ty.is_float() {
-        res = fx.bcx.ins().bitcast(ty, res);
+        res = codegen_bitcast(fx, ty, res);
     }
 
     res
@@ -240,10 +241,9 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
             substs,
             args,
             destination,
+            target,
             source_info.span,
         );
-        let ret_block = fx.get_block(target);
-        fx.bcx.ins().jump(ret_block, &[]);
     } else if codegen_float_intrinsic_call(fx, intrinsic, args, destination) {
         let ret_block = fx.get_block(target);
         fx.bcx.ins().jump(ret_block, &[]);
@@ -650,7 +650,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
             let layout = fx.layout_of(substs.type_at(0));
             if layout.abi.is_uninhabited() {
                 with_no_trimmed_paths!({
-                    crate::base::codegen_panic(
+                    crate::base::codegen_panic_nounwind(
                         fx,
                         &format!("attempted to instantiate uninhabited type `{}`", layout.ty),
                         source_info,
@@ -659,9 +659,11 @@ fn codegen_regular_intrinsic_call<'tcx>(
                 return;
             }
 
-            if intrinsic == sym::assert_zero_valid && !fx.tcx.permits_zero_init(layout) {
+            if intrinsic == sym::assert_zero_valid
+                && !fx.tcx.permits_zero_init(fx.param_env().and(layout))
+            {
                 with_no_trimmed_paths!({
-                    crate::base::codegen_panic(
+                    crate::base::codegen_panic_nounwind(
                         fx,
                         &format!(
                             "attempted to zero-initialize type `{}`, which is invalid",
@@ -674,10 +676,10 @@ fn codegen_regular_intrinsic_call<'tcx>(
             }
 
             if intrinsic == sym::assert_mem_uninitialized_valid
-                && !fx.tcx.permits_uninit_init(layout)
+                && !fx.tcx.permits_uninit_init(fx.param_env().and(layout))
             {
                 with_no_trimmed_paths!({
-                    crate::base::codegen_panic(
+                    crate::base::codegen_panic_nounwind(
                         fx,
                         &format!(
                             "attempted to leave type `{}` uninitialized, which is invalid",
index 14f5e9187399fac76f2a64d0147f2f647a904929..b33eb29754ab70e3fab43eeef4109e6962f99683 100644 (file)
@@ -24,6 +24,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
     _substs: SubstsRef<'tcx>,
     args: &[mir::Operand<'tcx>],
     ret: CPlace<'tcx>,
+    target: BasicBlock,
     span: Span,
 ) {
     match intrinsic {
@@ -277,16 +278,15 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             } else {
                 fx.tcx.sess.span_warn(span, "Index argument for `simd_extract` is not a constant");
                 let trap_block = fx.bcx.create_block();
-                let dummy_block = fx.bcx.create_block();
                 let true_ = fx.bcx.ins().iconst(types::I8, 1);
                 fx.bcx.ins().brnz(true_, trap_block, &[]);
-                fx.bcx.ins().jump(dummy_block, &[]);
+                let ret_block = fx.get_block(target);
+                fx.bcx.ins().jump(ret_block, &[]);
                 fx.bcx.switch_to_block(trap_block);
                 crate::trap::trap_unimplemented(
                     fx,
                     "Index argument for `simd_extract` is not a constant",
                 );
-                fx.bcx.switch_to_block(dummy_block);
                 return;
             };
 
@@ -770,11 +770,119 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             });
         }
 
-        // simd_arith_offset
-        // simd_scatter
-        // simd_gather
+        sym::simd_expose_addr | sym::simd_from_exposed_addr | sym::simd_cast_ptr => {
+            intrinsic_args!(fx, args => (arg); intrinsic);
+            ret.write_cvalue_transmute(fx, arg);
+        }
+
+        sym::simd_arith_offset => {
+            intrinsic_args!(fx, args => (ptr, offset); intrinsic);
+
+            let (lane_count, ptr_lane_ty) = ptr.layout().ty.simd_size_and_type(fx.tcx);
+            let pointee_ty = ptr_lane_ty.builtin_deref(true).unwrap().ty;
+            let pointee_size = fx.layout_of(pointee_ty).size.bytes();
+            let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
+            let ret_lane_layout = fx.layout_of(ret_lane_ty);
+            assert_eq!(lane_count, ret_lane_count);
+
+            for lane_idx in 0..lane_count {
+                let ptr_lane = ptr.value_lane(fx, lane_idx).load_scalar(fx);
+                let offset_lane = offset.value_lane(fx, lane_idx).load_scalar(fx);
+
+                let ptr_diff = if pointee_size != 1 {
+                    fx.bcx.ins().imul_imm(offset_lane, pointee_size as i64)
+                } else {
+                    offset_lane
+                };
+                let res_lane = fx.bcx.ins().iadd(ptr_lane, ptr_diff);
+                let res_lane = CValue::by_val(res_lane, ret_lane_layout);
+
+                ret.place_lane(fx, lane_idx).write_cvalue(fx, res_lane);
+            }
+        }
+
+        sym::simd_gather => {
+            intrinsic_args!(fx, args => (val, ptr, mask); intrinsic);
+
+            let (val_lane_count, val_lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
+            let (ptr_lane_count, _ptr_lane_ty) = ptr.layout().ty.simd_size_and_type(fx.tcx);
+            let (mask_lane_count, _mask_lane_ty) = mask.layout().ty.simd_size_and_type(fx.tcx);
+            let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
+            assert_eq!(val_lane_count, ptr_lane_count);
+            assert_eq!(val_lane_count, mask_lane_count);
+            assert_eq!(val_lane_count, ret_lane_count);
+
+            let lane_clif_ty = fx.clif_type(val_lane_ty).unwrap();
+            let ret_lane_layout = fx.layout_of(ret_lane_ty);
+
+            for lane_idx in 0..ptr_lane_count {
+                let val_lane = val.value_lane(fx, lane_idx).load_scalar(fx);
+                let ptr_lane = ptr.value_lane(fx, lane_idx).load_scalar(fx);
+                let mask_lane = mask.value_lane(fx, lane_idx).load_scalar(fx);
+
+                let if_enabled = fx.bcx.create_block();
+                let if_disabled = fx.bcx.create_block();
+                let next = fx.bcx.create_block();
+                let res_lane = fx.bcx.append_block_param(next, lane_clif_ty);
+
+                fx.bcx.ins().brnz(mask_lane, if_enabled, &[]);
+                fx.bcx.ins().jump(if_disabled, &[]);
+                fx.bcx.seal_block(if_enabled);
+                fx.bcx.seal_block(if_disabled);
+
+                fx.bcx.switch_to_block(if_enabled);
+                let res = fx.bcx.ins().load(lane_clif_ty, MemFlags::trusted(), ptr_lane, 0);
+                fx.bcx.ins().jump(next, &[res]);
+
+                fx.bcx.switch_to_block(if_disabled);
+                fx.bcx.ins().jump(next, &[val_lane]);
+
+                fx.bcx.seal_block(next);
+                fx.bcx.switch_to_block(next);
+
+                fx.bcx.ins().nop();
+
+                ret.place_lane(fx, lane_idx)
+                    .write_cvalue(fx, CValue::by_val(res_lane, ret_lane_layout));
+            }
+        }
+
+        sym::simd_scatter => {
+            intrinsic_args!(fx, args => (val, ptr, mask); intrinsic);
+
+            let (val_lane_count, _val_lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
+            let (ptr_lane_count, _ptr_lane_ty) = ptr.layout().ty.simd_size_and_type(fx.tcx);
+            let (mask_lane_count, _mask_lane_ty) = mask.layout().ty.simd_size_and_type(fx.tcx);
+            assert_eq!(val_lane_count, ptr_lane_count);
+            assert_eq!(val_lane_count, mask_lane_count);
+
+            for lane_idx in 0..ptr_lane_count {
+                let val_lane = val.value_lane(fx, lane_idx).load_scalar(fx);
+                let ptr_lane = ptr.value_lane(fx, lane_idx).load_scalar(fx);
+                let mask_lane = mask.value_lane(fx, lane_idx).load_scalar(fx);
+
+                let if_enabled = fx.bcx.create_block();
+                let next = fx.bcx.create_block();
+
+                fx.bcx.ins().brnz(mask_lane, if_enabled, &[]);
+                fx.bcx.ins().jump(next, &[]);
+                fx.bcx.seal_block(if_enabled);
+
+                fx.bcx.switch_to_block(if_enabled);
+                fx.bcx.ins().store(MemFlags::trusted(), val_lane, ptr_lane, 0);
+                fx.bcx.ins().jump(next, &[]);
+
+                fx.bcx.seal_block(next);
+                fx.bcx.switch_to_block(next);
+            }
+        }
+
         _ => {
-            fx.tcx.sess.span_fatal(span, &format!("Unknown SIMD intrinsic {}", intrinsic));
+            fx.tcx.sess.span_err(span, &format!("Unknown SIMD intrinsic {}", intrinsic));
+            // Prevent verifier error
+            fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
         }
     }
+    let ret_block = fx.get_block(target);
+    fx.bcx.ins().jump(ret_block, &[]);
 }
index 629d79d501240217d17ac3a6294ff338ed29300c..d3868730557b7e1e4da40a9f684e78be375dcd49 100644 (file)
@@ -57,6 +57,8 @@
 mod concurrency_limiter;
 mod config;
 mod constant;
+// FIXME revert back to the external crate with Cranelift 0.93
+mod cranelift_native;
 mod debuginfo;
 mod discriminant;
 mod driver;
@@ -278,12 +280,14 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar
         }
     }
 
-    if target_triple.architecture == target_lexicon::Architecture::X86_64 {
+    if let target_lexicon::Architecture::Aarch64(_) | target_lexicon::Architecture::X86_64 =
+        target_triple.architecture
+    {
         // Windows depends on stack probes to grow the committed part of the stack
         flags_builder.enable("enable_probestack").unwrap();
         flags_builder.set("probestack_strategy", "inline").unwrap();
     } else {
-        // __cranelift_probestack is not provided and inline stack probes are only supported on x86_64
+        // __cranelift_probestack is not provided and inline stack probes are only supported on AArch64 and x86_64
         flags_builder.set("enable_probestack", "false").unwrap();
     }
 
index c10054e7f0d2c971711364aafdfe563558e3fd5d..fd45362548c0dcc1f5d88ddda1a83c7555e71d70 100644 (file)
@@ -64,13 +64,20 @@ fn create_entry_fn(
             ],
             returns: vec![AbiParam::new(m.target_config().pointer_type() /*isize*/)],
             call_conv: crate::conv_to_call_conv(
+                tcx.sess,
                 tcx.sess.target.options.entry_abi,
                 m.target_config().default_call_conv,
             ),
         };
 
         let entry_name = tcx.sess.target.options.entry_name.as_ref();
-        let cmain_func_id = m.declare_function(entry_name, Linkage::Export, &cmain_sig).unwrap();
+        let cmain_func_id = match m.declare_function(entry_name, Linkage::Export, &cmain_sig) {
+            Ok(func_id) => func_id,
+            Err(err) => {
+                tcx.sess
+                    .fatal(&format!("entry symbol `{entry_name}` declared multiple times: {err}"));
+            }
+        };
 
         let instance = Instance::mono(tcx, rust_main_def_id).polymorphize(tcx);
 
@@ -162,7 +169,11 @@ fn create_entry_fn(
             bcx.seal_all_blocks();
             bcx.finalize();
         }
-        m.define_function(cmain_func_id, &mut ctx).unwrap();
+
+        if let Err(err) = m.define_function(cmain_func_id, &mut ctx) {
+            tcx.sess.fatal(&format!("entry symbol `{entry_name}` defined multiple times: {err}"));
+        }
+
         unwind_context.add_function(cmain_func_id, &ctx, m.isa());
     }
 }
index 7f45bbd8f28136a43b8271ba5f3e2755d19d522d..26327dca299b930da6a973b0683915c4634c78ae 100644 (file)
@@ -7,7 +7,7 @@
 /// otherwise return the given value and false.
 pub(crate) fn maybe_unwrap_bool_not(bcx: &mut FunctionBuilder<'_>, arg: Value) -> (Value, bool) {
     if let ValueDef::Result(arg_inst, 0) = bcx.func.dfg.value_def(arg) {
-        match bcx.func.dfg[arg_inst] {
+        match bcx.func.dfg.insts[arg_inst] {
             // This is the lowering of `Rvalue::Not`
             InstructionData::IntCompareImm {
                 opcode: Opcode::IcmpImm,
@@ -34,7 +34,7 @@ pub(crate) fn maybe_known_branch_taken(
         return None;
     };
 
-    match bcx.func.dfg[arg_inst] {
+    match bcx.func.dfg.insts[arg_inst] {
         InstructionData::UnaryImm { opcode: Opcode::Iconst, imm } => {
             if test_zero {
                 Some(imm.bits() == 0)
index fe8af21ac6de567cff94a34ec13e625f8876fe4a..fa06d6c3ba7f3a2a27b9f14b73d8862cfac75d87 100644 (file)
@@ -514,8 +514,8 @@ fn transmute_value<'tcx>(
                 (types::I32, types::F32)
                 | (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().bitcast(dst_ty, data),
+                | (types::F64, types::I64) => codegen_bitcast(fx, dst_ty, data),
+                _ if src_ty.is_vector() && dst_ty.is_vector() => codegen_bitcast(fx, 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 {
index 02e1e21ade1de98f4d72256adbe70755a3997a55..fd825d02e355c0bfd3f58a6a8e99a33806ab33be 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 --edition 2021
+rustc $0 -o ${0/.rs/.bin} -Cdebuginfo=1 --edition 2021 -Cpanic=abort
 exec ${0/.rs/.bin} $@
 */
 
index a92242b2615c1f66b1cfb438c61a0bbf48ad0e97..e88c12716ecd3d240da161bd05e7c7900067a39b 100644 (file)
@@ -709,7 +709,7 @@ fn scalar_load_metadata<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, load:
                         bx.range_metadata(load, vr);
                     }
                 }
-                abi::Pointer if vr.start < vr.end && !vr.contains(0) => {
+                abi::Pointer(_) if vr.start < vr.end && !vr.contains(0) => {
                     bx.nonnull_metadata(load);
                 }
                 _ => {}
index 0afc56b4494d3a237948dd508dbd4e5c00bf9cac..c939da9cec3c21346be0ed6b5db214830bb858b1 100644 (file)
@@ -211,7 +211,7 @@ fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) ->
                 let base_addr = self.const_bitcast(base_addr, self.usize_type);
                 let offset = self.context.new_rvalue_from_long(self.usize_type, offset.bytes() as i64);
                 let ptr = self.const_bitcast(base_addr + offset, ptr_type);
-                if layout.primitive() != Pointer {
+                if !matches!(layout.primitive(), Pointer(_)) {
                     self.const_bitcast(ptr.dereference(None).to_rvalue(), ty)
                 }
                 else {
index ea8ab76114604208ed7a9b619dc257e4e9e9c4ff..dc41cb761b59c44b9e60d2567d3b5b5b276a315f 100644 (file)
@@ -322,13 +322,16 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: ConstAl
             )
             .expect("const_alloc_to_llvm: could not read relocation pointer")
             as u64;
+
+        let address_space = cx.tcx.global_alloc(alloc_id).address_space(cx);
+
         llvals.push(cx.scalar_to_backend(
             InterpScalar::from_pointer(
                 interpret::Pointer::new(alloc_id, Size::from_bytes(ptr_offset)),
                 &cx.tcx,
             ),
-            abi::Scalar::Initialized { value: Primitive::Pointer, valid_range: WrappingRange::full(dl.pointer_size) },
-            cx.type_i8p(),
+            abi::Scalar::Initialized { value: Primitive::Pointer(address_space), valid_range: WrappingRange::full(dl.pointer_size) },
+            cx.type_i8p_ext(address_space),
         ));
         next_offset = offset + pointer_size;
     }
index 524d10fb5e24d02e52829d96d0b5a970850d1c6e..1326af670cde4e4cc78f3eb1e48eabb79eaf39bb 100644 (file)
@@ -253,7 +253,7 @@ fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Sca
             Int(i, false) => cx.type_from_unsigned_integer(i),
             F32 => cx.type_f32(),
             F64 => cx.type_f64(),
-            Pointer => {
+            Pointer(address_space) => {
                 // If we know the alignment, pick something better than i8.
                 let pointee =
                     if let Some(pointee) = self.pointee_info_at(cx, offset) {
@@ -262,7 +262,7 @@ fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Sca
                     else {
                         cx.type_i8()
                     };
-                cx.type_ptr_to(pointee)
+                cx.type_ptr_to_ext(pointee, address_space)
             }
         }
     }
index 52c8b51796c0bf7712e38ddfb44bca2f64c4bdb5..d9f8170a3cffa0617172e93f5d0d5d4a0038efdd 100644 (file)
@@ -849,6 +849,7 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
 /// Helper function to get the LLVM type for a Scalar. Pointers are returned as
 /// the equivalent integer type.
 fn llvm_asm_scalar_type<'ll>(cx: &CodegenCx<'ll, '_>, scalar: Scalar) -> &'ll Type {
+    let dl = &cx.tcx.data_layout;
     match scalar.primitive() {
         Primitive::Int(Integer::I8, _) => cx.type_i8(),
         Primitive::Int(Integer::I16, _) => cx.type_i16(),
@@ -856,7 +857,8 @@ fn llvm_asm_scalar_type<'ll>(cx: &CodegenCx<'ll, '_>, scalar: Scalar) -> &'ll Ty
         Primitive::Int(Integer::I64, _) => cx.type_i64(),
         Primitive::F32 => cx.type_f32(),
         Primitive::F64 => cx.type_f64(),
-        Primitive::Pointer => cx.type_isize(),
+        // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
+        Primitive::Pointer(_) => cx.type_from_integer(dl.ptr_sized_integer()),
         _ => unreachable!(),
     }
 }
@@ -868,6 +870,7 @@ fn llvm_fixup_input<'ll, 'tcx>(
     reg: InlineAsmRegClass,
     layout: &TyAndLayout<'tcx>,
 ) -> &'ll Value {
+    let dl = &bx.tcx.data_layout;
     match (reg, layout.abi) {
         (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg), Abi::Scalar(s)) => {
             if let Primitive::Int(Integer::I8, _) = s.primitive() {
@@ -881,8 +884,10 @@ fn llvm_fixup_input<'ll, 'tcx>(
             let elem_ty = llvm_asm_scalar_type(bx.cx, s);
             let count = 16 / layout.size.bytes();
             let vec_ty = bx.cx.type_vector(elem_ty, count);
-            if let Primitive::Pointer = s.primitive() {
-                value = bx.ptrtoint(value, bx.cx.type_isize());
+            // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
+            if let Primitive::Pointer(_) = s.primitive() {
+                let t = bx.type_from_integer(dl.ptr_sized_integer());
+                value = bx.ptrtoint(value, t);
             }
             bx.insert_element(bx.const_undef(vec_ty), value, bx.const_i32(0))
         }
@@ -958,7 +963,7 @@ fn llvm_fixup_output<'ll, 'tcx>(
         }
         (InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16), Abi::Scalar(s)) => {
             value = bx.extract_element(value, bx.const_i32(0));
-            if let Primitive::Pointer = s.primitive() {
+            if let Primitive::Pointer(_) = s.primitive() {
                 value = bx.inttoptr(value, layout.llvm_type(bx.cx));
             }
             value
index 5e98deae48aa2dae049de2e28fad05c4df7a256e..0f33b98548984877a230edeb0004e8ba403e7132 100644 (file)
@@ -511,7 +511,7 @@ fn scalar_load_metadata<'a, 'll, 'tcx>(
                         bx.range_metadata(load, scalar.valid_range(bx));
                     }
                 }
-                abi::Pointer => {
+                abi::Pointer(_) => {
                     if !scalar.valid_range(bx).contains(0) {
                         bx.nonnull_metadata(load);
                     }
index acee9134fb96e48a26c3d4eb7a465c8d66ac6bf9..edb1c160626ea7cf3a24b89e9d61541bbd887b17 100644 (file)
@@ -236,7 +236,7 @@ fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) ->
             Scalar::Int(int) => {
                 let data = int.assert_bits(layout.size(self));
                 let llval = self.const_uint_big(self.type_ix(bitsize), data);
-                if layout.primitive() == Pointer {
+                if matches!(layout.primitive(), Pointer(_)) {
                     unsafe { llvm::LLVMConstIntToPtr(llval, llty) }
                 } else {
                     self.const_bitcast(llval, llty)
@@ -284,7 +284,7 @@ fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: &'ll Type) ->
                         1,
                     )
                 };
-                if layout.primitive() != Pointer {
+                if !matches!(layout.primitive(), Pointer(_)) {
                     unsafe { llvm::LLVMConstPtrToInt(llval, llty) }
                 } else {
                     self.const_bitcast(llval, llty)
index 16467b614feafd3015d192b3734244dee1a6058a..cad3c5d87b73c6bf445a15a08bf8f99702f40e2f 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::interpret::{
-    read_target_uint, Allocation, ConstAllocation, ErrorHandled, GlobalAlloc, InitChunk, Pointer,
+    read_target_uint, Allocation, ConstAllocation, ErrorHandled, InitChunk, Pointer,
     Scalar as InterpScalar,
 };
 use rustc_middle::mir::mono::MonoItem;
@@ -21,9 +21,7 @@
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_middle::{bug, span_bug};
 use rustc_session::config::Lto;
-use rustc_target::abi::{
-    AddressSpace, Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange,
-};
+use rustc_target::abi::{Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange};
 use std::ops::Range;
 
 pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<'_>) -> &'ll Value {
@@ -98,12 +96,7 @@ fn append_chunks_of_init_and_uninit_bytes<'ll, 'a, 'b>(
         .expect("const_alloc_to_llvm: could not read relocation pointer")
             as u64;
 
-        let address_space = match cx.tcx.global_alloc(alloc_id) {
-            GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space,
-            GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => {
-                AddressSpace::DATA
-            }
-        };
+        let address_space = cx.tcx.global_alloc(alloc_id).address_space(cx);
 
         llvals.push(cx.scalar_to_backend(
             InterpScalar::from_pointer(
@@ -111,7 +104,7 @@ fn append_chunks_of_init_and_uninit_bytes<'ll, 'a, 'b>(
                 &cx.tcx,
             ),
             Scalar::Initialized {
-                value: Primitive::Pointer,
+                value: Primitive::Pointer(address_space),
                 valid_range: WrappingRange::full(dl.pointer_size),
             },
             cx.type_i8p_ext(address_space),
index 22c61248b7d53275fa3e8a662c93ad7f7ae83775..d9a73c7a5c9043fe42934215ee4789e974010fe6 100644 (file)
@@ -1,6 +1,5 @@
 use crate::common::CodegenCx;
 use crate::coverageinfo;
-use crate::errors::InstrumentCoverageRequiresLLVM12;
 use crate::llvm;
 
 use llvm::coverageinfo::CounterMappingRegion;
@@ -19,8 +18,8 @@
 
 /// Generates and exports the Coverage Map.
 ///
-/// Rust Coverage Map generation supports LLVM Coverage Mapping Format versions
-/// 5 (LLVM 12, only) and 6 (zero-based encoded as 4 and 5, respectively), as defined at
+/// Rust Coverage Map generation supports LLVM Coverage Mapping Format version
+/// 6 (zero-based encoded as 5), as defined at
 /// [LLVM Code Coverage Mapping Format](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/docs/CoverageMappingFormat.rst#llvm-code-coverage-mapping-format).
 /// These versions are supported by the LLVM coverage tools (`llvm-profdata` and `llvm-cov`)
 /// bundled with Rust's fork of LLVM.
 pub fn finalize(cx: &CodegenCx<'_, '_>) {
     let tcx = cx.tcx;
 
-    // Ensure the installed version of LLVM supports at least Coverage Map
-    // Version 5 (encoded as a zero-based value: 4), which was introduced with
-    // LLVM 12.
+    // Ensure the installed version of LLVM supports Coverage Map Version 6
+    // (encoded as a zero-based value: 5), which was introduced with LLVM 13.
     let version = coverageinfo::mapping_version();
-    if version < 4 {
-        tcx.sess.emit_fatal(InstrumentCoverageRequiresLLVM12);
-    }
+    assert_eq!(version, 5, "The `CoverageMappingVersion` exposed by `llvm-wrapper` is out of sync");
 
     debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name());
 
@@ -61,7 +57,7 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
         return;
     }
 
-    let mut mapgen = CoverageMapGenerator::new(tcx, version);
+    let mut mapgen = CoverageMapGenerator::new(tcx);
 
     // Encode coverage mappings and generate function records
     let mut function_data = Vec::new();
@@ -124,25 +120,18 @@ struct CoverageMapGenerator {
 }
 
 impl CoverageMapGenerator {
-    fn new(tcx: TyCtxt<'_>, version: u32) -> Self {
+    fn new(tcx: TyCtxt<'_>) -> Self {
         let mut filenames = FxIndexSet::default();
-        if version >= 5 {
-            // LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
-            // requires setting the first filename to the compilation directory.
-            // Since rustc generates coverage maps with relative paths, the
-            // compilation directory can be combined with the relative paths
-            // to get absolute paths, if needed.
-            let working_dir = tcx
-                .sess
-                .opts
-                .working_dir
-                .remapped_path_if_available()
-                .to_string_lossy()
-                .to_string();
-            let c_filename =
-                CString::new(working_dir).expect("null error converting filename to C string");
-            filenames.insert(c_filename);
-        }
+        // LLVM Coverage Mapping Format version 6 (zero-based encoded as 5)
+        // requires setting the first filename to the compilation directory.
+        // Since rustc generates coverage maps with relative paths, the
+        // compilation directory can be combined with the relative paths
+        // to get absolute paths, if needed.
+        let working_dir =
+            tcx.sess.opts.working_dir.remapped_path_if_available().to_string_lossy().to_string();
+        let c_filename =
+            CString::new(working_dir).expect("null error converting filename to C string");
+        filenames.insert(c_filename);
         Self { filenames }
     }
 
index 564ab351bd41ffbd0d55ebc3e57f2072d1cda594..54e850f25996b0d1894b038e197480f581ab630e 100644 (file)
@@ -122,7 +122,8 @@ fn tag_base_type<'ll, 'tcx>(
                 Primitive::Int(t, _) => t,
                 Primitive::F32 => Integer::I32,
                 Primitive::F64 => Integer::I64,
-                Primitive::Pointer => {
+                // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
+                Primitive::Pointer(_) => {
                     // If the niche is the NULL value of a reference, then `discr_enum_ty` will be
                     // a RawPtr. CodeView doesn't know what to do with enums whose base type is a
                     // pointer so we fix this up to just be `usize`.
index b46209972421fe894fd4b217013d7072558d6682..001d1ce93d8b479ee6184658373b78504813dab9 100644 (file)
@@ -39,10 +39,6 @@ pub(crate) struct ErrorCreatingImportLibrary<'a> {
     pub error: String,
 }
 
-#[derive(Diagnostic)]
-#[diag(codegen_llvm_instrument_coverage_requires_llvm_12)]
-pub(crate) struct InstrumentCoverageRequiresLLVM12;
-
 #[derive(Diagnostic)]
 #[diag(codegen_llvm_symbol_already_defined)]
 pub(crate) struct SymbolAlreadyDefined<'a> {
index a6a75eff9a36d24e0c331aa3e171f09b3f839ebc..dd89c4c59c14d83e0ac639f5557e628b26ac17ff 100644 (file)
@@ -149,7 +149,7 @@ fn codegen_intrinsic_call(
                                     emit_va_arg(self, args[0], ret_ty)
                                 }
                             }
-                            Primitive::F64 | Primitive::Pointer => {
+                            Primitive::F64 | Primitive::Pointer(_) => {
                                 emit_va_arg(self, args[0], ret_ty)
                             }
                             // `va_arg` should never be used with the return type f32.
index 75cd5df972316366807d06a8d5cfa4d6a399ff0a..c73d233b767a41cb20720ebd1696a7a9ec0f04b0 100644 (file)
@@ -7,7 +7,7 @@
 use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
 use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 use rustc_middle::ty::{self, Ty, TypeVisitable};
-use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape};
+use rustc_target::abi::{Abi, Align, FieldsShape};
 use rustc_target::abi::{Int, Pointer, F32, F64};
 use rustc_target::abi::{PointeeInfo, Scalar, Size, TyAbiInterface, Variants};
 use smallvec::{smallvec, SmallVec};
@@ -312,14 +312,13 @@ fn scalar_llvm_type_at<'a>(
             Int(i, _) => cx.type_from_integer(i),
             F32 => cx.type_f32(),
             F64 => cx.type_f64(),
-            Pointer => {
+            Pointer(address_space) => {
                 // If we know the alignment, pick something better than i8.
-                let (pointee, address_space) =
-                    if let Some(pointee) = self.pointee_info_at(cx, offset) {
-                        (cx.type_pointee_for_align(pointee.align), pointee.address_space)
-                    } else {
-                        (cx.type_i8(), AddressSpace::DATA)
-                    };
+                let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) {
+                    cx.type_pointee_for_align(pointee.align)
+                } else {
+                    cx.type_i8()
+                };
                 cx.type_ptr_to_ext(pointee, address_space)
             }
         }
index b148e4185a68a795ce5f2c02e8e164dbcee8cada..4ac7bea03ebc01e7a77abcfb8597673e3bf0d3ca 100644 (file)
@@ -599,7 +599,8 @@ fn link_dwarf_object<'a>(
     cg_results: &CodegenResults,
     executable_out_filename: &Path,
 ) {
-    let dwp_out_filename = executable_out_filename.with_extension("dwp");
+    let mut dwp_out_filename = executable_out_filename.to_path_buf().into_os_string();
+    dwp_out_filename.push(".dwp");
     debug!(?dwp_out_filename, ?executable_out_filename);
 
     #[derive(Default)]
@@ -1300,12 +1301,6 @@ fn preserve_objects_for_their_debuginfo(sess: &Session) -> (bool, bool) {
         return (false, false);
     }
 
-    // If we're only producing artifacts that are archives, no need to preserve
-    // the objects as they're losslessly contained inside the archives.
-    if sess.crate_types().iter().all(|&x| x.is_archive()) {
-        return (false, false);
-    }
-
     match (sess.split_debuginfo(), sess.opts.unstable_opts.split_dwarf_kind) {
         // If there is no split debuginfo then do not preserve objects.
         (SplitDebuginfo::Off, _) => (false, false),
index 978aff511bfa74d07f2ecbcc4a20aa3155d2e62d..2623a650e07b28f4c86e30263a192c90a7ec0814 100644 (file)
@@ -39,7 +39,6 @@ enum MergingSucc {
 struct TerminatorCodegenHelper<'tcx> {
     bb: mir::BasicBlock,
     terminator: &'tcx mir::Terminator<'tcx>,
-    funclet_bb: Option<mir::BasicBlock>,
 }
 
 impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
@@ -49,28 +48,24 @@ fn funclet<'b, Bx: BuilderMethods<'a, 'tcx>>(
         &self,
         fx: &'b mut FunctionCx<'a, 'tcx, Bx>,
     ) -> Option<&'b Bx::Funclet> {
-        let funclet_bb = self.funclet_bb?;
-        if base::wants_msvc_seh(fx.cx.tcx().sess) {
-            // If `landing_pad_for` hasn't been called yet to create the `Funclet`,
-            // it has to be now. This may not seem necessary, as RPO should lead
-            // to all the unwind edges being visited (and so to `landing_pad_for`
-            // getting called for them), before building any of the blocks inside
-            // the funclet itself - however, if MIR contains edges that end up not
-            // being needed in the LLVM IR after monomorphization, the funclet may
-            // be unreachable, and we don't have yet a way to skip building it in
-            // such an eventuality (which may be a better solution than this).
-            if fx.funclets[funclet_bb].is_none() {
-                fx.landing_pad_for(funclet_bb);
-            }
-
-            Some(
-                fx.funclets[funclet_bb]
-                    .as_ref()
-                    .expect("landing_pad_for didn't also create funclets entry"),
-            )
-        } else {
-            None
+        let cleanup_kinds = (&fx.cleanup_kinds).as_ref()?;
+        let funclet_bb = cleanup_kinds[self.bb].funclet_bb(self.bb)?;
+        // If `landing_pad_for` hasn't been called yet to create the `Funclet`,
+        // it has to be now. This may not seem necessary, as RPO should lead
+        // to all the unwind edges being visited (and so to `landing_pad_for`
+        // getting called for them), before building any of the blocks inside
+        // the funclet itself - however, if MIR contains edges that end up not
+        // being needed in the LLVM IR after monomorphization, the funclet may
+        // be unreachable, and we don't have yet a way to skip building it in
+        // such an eventuality (which may be a better solution than this).
+        if fx.funclets[funclet_bb].is_none() {
+            fx.landing_pad_for(funclet_bb);
         }
+        Some(
+            fx.funclets[funclet_bb]
+                .as_ref()
+                .expect("landing_pad_for didn't also create funclets entry"),
+        )
     }
 
     /// Get a basic block (creating it if necessary), possibly with cleanup
@@ -104,23 +99,24 @@ fn llbb_characteristics<Bx: BuilderMethods<'a, 'tcx>>(
         fx: &mut FunctionCx<'a, 'tcx, Bx>,
         target: mir::BasicBlock,
     ) -> (bool, bool) {
-        let target_funclet = fx.cleanup_kinds[target].funclet_bb(target);
-        let (needs_landing_pad, is_cleanupret) = match (self.funclet_bb, target_funclet) {
-            (None, None) => (false, false),
-            (None, Some(_)) => (true, false),
-            (Some(_), None) => {
-                let span = self.terminator.source_info.span;
-                span_bug!(span, "{:?} - jump out of cleanup?", self.terminator);
-            }
-            (Some(f), Some(t_f)) => {
-                if f == t_f || !base::wants_msvc_seh(fx.cx.tcx().sess) {
-                    (false, false)
-                } else {
-                    (true, true)
+        if let Some(ref cleanup_kinds) = fx.cleanup_kinds {
+            let funclet_bb = cleanup_kinds[self.bb].funclet_bb(self.bb);
+            let target_funclet = cleanup_kinds[target].funclet_bb(target);
+            let (needs_landing_pad, is_cleanupret) = match (funclet_bb, target_funclet) {
+                (None, None) => (false, false),
+                (None, Some(_)) => (true, false),
+                (Some(f), Some(t_f)) => (f != t_f, f != t_f),
+                (Some(_), None) => {
+                    let span = self.terminator.source_info.span;
+                    span_bug!(span, "{:?} - jump out of cleanup?", self.terminator);
                 }
-            }
-        };
-        (needs_landing_pad, is_cleanupret)
+            };
+            (needs_landing_pad, is_cleanupret)
+        } else {
+            let needs_landing_pad = !fx.mir[self.bb].is_cleanup && fx.mir[target].is_cleanup;
+            let is_cleanupret = false;
+            (needs_landing_pad, is_cleanupret)
+        }
     }
 
     fn funclet_br<Bx: BuilderMethods<'a, 'tcx>>(
@@ -678,8 +674,8 @@ enum AssertIntrinsic {
             let layout = bx.layout_of(ty);
             let do_panic = match intrinsic {
                 Inhabited => layout.abi.is_uninhabited(),
-                ZeroValid => !bx.tcx().permits_zero_init(layout),
-                MemUninitializedValid => !bx.tcx().permits_uninit_init(layout),
+                ZeroValid => !bx.tcx().permits_zero_init(bx.param_env().and(layout)),
+                MemUninitializedValid => !bx.tcx().permits_uninit_init(bx.param_env().and(layout)),
             };
             Some(if do_panic {
                 let msg_str = with_no_visible_paths!({
@@ -1253,9 +1249,7 @@ fn codegen_terminator(
     ) -> MergingSucc {
         debug!("codegen_terminator: {:?}", terminator);
 
-        // Create the cleanup bundle, if needed.
-        let funclet_bb = self.cleanup_kinds[bb].funclet_bb(bb);
-        let helper = TerminatorCodegenHelper { bb, terminator, funclet_bb };
+        let helper = TerminatorCodegenHelper { bb, terminator };
 
         let mergeable_succ = || {
             // Note: any call to `switch_to_block` will invalidate a `true` value
@@ -1801,8 +1795,8 @@ 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.
-                let src_is_ptr = src_scalar.primitive() == abi::Pointer;
-                let dst_is_ptr = dst_scalar.primitive() == abi::Pointer;
+                let src_is_ptr = matches!(src_scalar.primitive(), abi::Pointer(_));
+                let dst_is_ptr = matches!(dst_scalar.primitive(), abi::Pointer(_));
                 if src_is_ptr == dst_is_ptr {
                     assert_eq!(src.layout.size, dst.layout.size);
 
index 79c66a955e76d856cb534aef6a6da2a6ff9cf107..bb265b8289ed977364b8126ffbba2459eec18f2d 100644 (file)
@@ -1,3 +1,4 @@
+use crate::base;
 use crate::traits::*;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
@@ -58,7 +59,7 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
     cached_llbbs: IndexVec<mir::BasicBlock, CachedLlbb<Bx::BasicBlock>>,
 
     /// The funclet status of each basic block
-    cleanup_kinds: IndexVec<mir::BasicBlock, analyze::CleanupKind>,
+    cleanup_kinds: Option<IndexVec<mir::BasicBlock, analyze::CleanupKind>>,
 
     /// When targeting MSVC, this stores the cleanup info for each funclet BB.
     /// This is initialized at the same time as the `landing_pads` entry for the
@@ -166,7 +167,9 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         start_bx.set_personality_fn(cx.eh_personality());
     }
 
-    let cleanup_kinds = analyze::cleanup_kinds(&mir);
+    let cleanup_kinds =
+        if base::wants_msvc_seh(cx.tcx().sess) { Some(analyze::cleanup_kinds(&mir)) } else { None };
+
     let cached_llbbs: IndexVec<mir::BasicBlock, CachedLlbb<Bx::BasicBlock>> =
         mir.basic_blocks
             .indices()
index fbe30154a7c8d26b23cb4af4ac5fa419e2a558ad..cf02f59f67b97c3470c281d511ed4ade1390ec84 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, Ty};
-use rustc_target::abi::{Abi, Align, FieldsShape, Int, TagEncoding};
+use rustc_target::abi::{Abi, Align, FieldsShape, Int, Pointer, TagEncoding};
 use rustc_target::abi::{VariantIdx, Variants};
 
 #[derive(Copy, Clone, Debug)]
@@ -209,6 +209,7 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
         bx: &mut Bx,
         cast_to: Ty<'tcx>,
     ) -> V {
+        let dl = &bx.tcx().data_layout;
         let cast_to_layout = bx.cx().layout_of(cast_to);
         let cast_to_size = cast_to_layout.layout.size();
         let cast_to = bx.cx().immediate_backend_type(cast_to_layout);
@@ -250,12 +251,14 @@ pub fn codegen_get_discr<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
             TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => {
                 // Cast to an integer so we don't have to treat a pointer as a
                 // special case.
-                let (tag, tag_llty) = if tag_scalar.primitive().is_ptr() {
-                    let t = bx.type_isize();
-                    let tag = bx.ptrtoint(tag_imm, t);
-                    (tag, t)
-                } else {
-                    (tag_imm, bx.cx().immediate_backend_type(tag_op.layout))
+                let (tag, tag_llty) = match tag_scalar.primitive() {
+                    // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
+                    Pointer(_) => {
+                        let t = bx.type_from_integer(dl.ptr_sized_integer());
+                        let tag = bx.ptrtoint(tag_imm, t);
+                        (tag, t)
+                    }
+                    _ => (tag_imm, bx.cx().immediate_backend_type(tag_op.layout)),
                 };
 
                 let tag_size = tag_scalar.size(bx.cx());
index cc7b6c91b607426e57cd6ff9b65b597eb8b4d54e..f87e4fbc1a17809105391a98722d7f881e72e071 100644 (file)
@@ -447,7 +447,7 @@ pub fn emulate_intrinsic(
                 }
 
                 if intrinsic_name == sym::assert_zero_valid {
-                    let should_panic = !self.tcx.permits_zero_init(layout);
+                    let should_panic = !self.tcx.permits_zero_init(self.param_env.and(layout));
 
                     if should_panic {
                         M::abort(
@@ -461,7 +461,7 @@ pub fn emulate_intrinsic(
                 }
 
                 if intrinsic_name == sym::assert_mem_uninitialized_valid {
-                    let should_panic = !self.tcx.permits_uninit_init(layout);
+                    let should_panic = !self.tcx.permits_uninit_init(self.param_env.and(layout));
 
                     if should_panic {
                         M::abort(
index befc0928f3debd253efecb036e95d991b02be214..a1b3985dce4e6ecfa27ff80b225e28e28f1d9d91 100644 (file)
@@ -319,7 +319,7 @@ fn read_immediate_from_mplace_raw(
                 assert_eq!(size, mplace.layout.size, "abi::Scalar size does not match layout size");
                 let scalar = alloc.read_scalar(
                     alloc_range(Size::ZERO, size),
-                    /*read_provenance*/ s.is_ptr(),
+                    /*read_provenance*/ matches!(s, abi::Pointer(_)),
                 )?;
                 Some(ImmTy { imm: scalar.into(), layout: mplace.layout })
             }
@@ -335,11 +335,11 @@ fn read_immediate_from_mplace_raw(
                 assert!(b_offset.bytes() > 0); // in `operand_field` we use the offset to tell apart the fields
                 let a_val = alloc.read_scalar(
                     alloc_range(Size::ZERO, a_size),
-                    /*read_provenance*/ a.is_ptr(),
+                    /*read_provenance*/ matches!(a, abi::Pointer(_)),
                 )?;
                 let b_val = alloc.read_scalar(
                     alloc_range(b_offset, b_size),
-                    /*read_provenance*/ b.is_ptr(),
+                    /*read_provenance*/ matches!(b, abi::Pointer(_)),
                 )?;
                 Some(ImmTy { imm: Immediate::ScalarPair(a_val, b_val), layout: mplace.layout })
             }
index 57b91df2d0708f8f06e35438518c51b6f148df6c..51624a0c6c817bb4a5327cd3cf1e744a75329772 100644 (file)
@@ -58,7 +58,12 @@ pub fn provide(providers: &mut Providers) {
         let (param_env, value) = param_env_and_value.into_parts();
         const_eval::deref_mir_constant(tcx, param_env, value)
     };
-    providers.permits_uninit_init =
-        |tcx, ty| util::might_permit_raw_init(tcx, ty, InitKind::UninitMitigated0x01Fill);
-    providers.permits_zero_init = |tcx, ty| util::might_permit_raw_init(tcx, ty, InitKind::Zero);
+    providers.permits_uninit_init = |tcx, param_env_and_ty| {
+        let (param_env, ty) = param_env_and_ty.into_parts();
+        util::might_permit_raw_init(tcx, param_env, ty, InitKind::UninitMitigated0x01Fill)
+    };
+    providers.permits_zero_init = |tcx, param_env_and_ty| {
+        let (param_env, ty) = param_env_and_ty.into_parts();
+        util::might_permit_raw_init(tcx, param_env, ty, InitKind::Zero)
+    };
 }
index dd168a9ac3cd3e94078cc20e24fb4c18c4b1b35c..3f83d40755ad8ea49116e5f2fa5cb538206da37d 100644 (file)
@@ -13,7 +13,7 @@
     ProjectionElem, RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind,
     Terminator, TerminatorKind, UnOp, START_BLOCK,
 };
-use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt};
 use rustc_mir_dataflow::impls::MaybeStorageLive;
 use rustc_mir_dataflow::storage::always_storage_live_locals;
 use rustc_mir_dataflow::{Analysis, ResultsCursor};
@@ -230,11 +230,6 @@ fn mir_assign_valid_types(&self, src: Ty<'tcx>, dest: Ty<'tcx>) -> bool {
             // Equal types, all is good.
             return true;
         }
-        // Normalization reveals opaque types, but we may be validating MIR while computing
-        // said opaque types, causing cycles.
-        if (src, dest).has_opaque_types() {
-            return true;
-        }
 
         crate::util::is_subtype(self.tcx, self.param_env, src, dest)
     }
index 4ce107ea68d4f0f3869cebe3cce00c706a42f58d..48961b7aac64588486695ddc2ba4b61d4a036117 100644 (file)
 /// to the full uninit check).
 pub fn might_permit_raw_init<'tcx>(
     tcx: TyCtxt<'tcx>,
+    param_env: ParamEnv<'tcx>,
     ty: TyAndLayout<'tcx>,
     kind: InitKind,
 ) -> bool {
     if tcx.sess.opts.unstable_opts.strict_init_checks {
         might_permit_raw_init_strict(ty, tcx, kind)
     } else {
-        let layout_cx = LayoutCx { tcx, param_env: ParamEnv::reveal_all() };
+        let layout_cx = LayoutCx { tcx, param_env };
         might_permit_raw_init_lax(ty, &layout_cx, kind)
     }
 }
index 10e673cd9297bda67fddcec349af9f5657a7eaf5..dda422c6dd07ee60cb67674282b657d053976890 100644 (file)
@@ -139,8 +139,7 @@ pub enum ProcessResult<O, E> {
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
 struct ObligationTreeId(usize);
 
-type ObligationTreeIdGenerator =
-    std::iter::Map<std::ops::RangeFrom<usize>, fn(usize) -> ObligationTreeId>;
+type ObligationTreeIdGenerator = impl Iterator<Item = ObligationTreeId>;
 
 pub struct ObligationForest<O: ForestObligation> {
     /// The list of obligations. In between calls to [Self::process_obligations],
index f50ad0137b88aacff80bed38c6e5caeccf54cc11..ccefd6adaf14b6012a614e96368d46b83919a3ad 100644 (file)
@@ -296,9 +296,8 @@ fn run_compiler(
 
             if let Some(ppm) = &sess.opts.pretty {
                 if ppm.needs_ast_map() {
-                    let expanded_crate = queries.expansion()?.borrow().0.clone();
                     queries.global_ctxt()?.enter(|tcx| {
-                        pretty::print_after_hir_lowering(tcx, &*expanded_crate, *ppm);
+                        pretty::print_after_hir_lowering(tcx, *ppm);
                         Ok(())
                     })?;
                 } else {
@@ -328,11 +327,15 @@ fn run_compiler(
                 }
             }
 
-            queries.global_ctxt()?;
+            let mut gctxt = queries.global_ctxt()?;
             if callbacks.after_expansion(compiler, queries) == Compilation::Stop {
                 return early_exit();
             }
 
+            // Make sure the `output_filenames` query is run for its side
+            // effects of writing the dep-info and reporting errors.
+            gctxt.enter(|tcx| tcx.output_filenames(()));
+
             if sess.opts.output_types.contains_key(&OutputType::DepInfo)
                 && sess.opts.output_types.len() == 1
             {
@@ -343,7 +346,7 @@ fn run_compiler(
                 return early_exit();
             }
 
-            queries.global_ctxt()?.enter(|tcx| {
+            gctxt.enter(|tcx| {
                 let result = tcx.analysis(());
                 if sess.opts.unstable_opts.save_analysis {
                     let crate_name = tcx.crate_name(LOCAL_CRATE);
@@ -360,6 +363,8 @@ fn run_compiler(
                 result
             })?;
 
+            drop(gctxt);
+
             if callbacks.after_analysis(compiler, queries) == Compilation::Stop {
                 return early_exit();
             }
index ae3ac8625b1862ca109c1a216329268abc6a6557..022051e008e32cfa192c60e88655f2c6f42670ae 100644 (file)
@@ -403,7 +403,7 @@ pub fn print_after_parsing(sess: &Session, krate: &ast::Crate, ppm: PpMode) {
     write_or_print(&out, sess);
 }
 
-pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, krate: &ast::Crate, ppm: PpMode) {
+pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, ppm: PpMode) {
     if ppm.needs_analysis() {
         abort_on_err(print_with_analysis(tcx, ppm), tcx.sess);
         return;
@@ -420,7 +420,7 @@ pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, krate: &ast::Crate, ppm
                 let parse = &sess.parse_sess;
                 pprust::print_crate(
                     sess.source_map(),
-                    krate,
+                    &tcx.resolver_for_lowering(()).borrow().1,
                     src_name,
                     src,
                     annotation.pp_ann(),
@@ -433,7 +433,7 @@ pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, krate: &ast::Crate, ppm
 
         AstTree(PpAstTreeMode::Expanded) => {
             debug!("pretty-printing expanded AST");
-            format!("{krate:#?}")
+            format!("{:#?}", tcx.resolver_for_lowering(()).borrow().1)
         }
 
         Hir(s) => call_with_pp_support_hir(&s, tcx, move |annotation, hir_map| {
index 9e4332c428386ff068dd0a2f49ba859cd3b758d4..0021638c10268c9ce5fcf68c7ffac5d0793d570c 100644 (file)
@@ -123,4 +123,7 @@ borrowck_cannot_move_when_borrowed =
 
 borrowck_opaque_type_non_generic_param =
     expected generic {$kind} parameter, found `{$ty}`
-    .label = this generic parameter must be used with a generic {$kind} parameter
+    .label = {STREQ($ty, "'static") ->
+        [true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
+        *[other] this generic parameter must be used with a generic {$kind} parameter
+    }
index 860212b051f39c4a8739110e9bf1edf220aa23cf..b82c903290b9a2c10c42db4fcfd036335bbdd8d4 100644 (file)
@@ -11,9 +11,6 @@ codegen_llvm_unknown_ctarget_feature_prefix =
 codegen_llvm_error_creating_import_library =
     Error creating import library for {$lib_name}: {$error}
 
-codegen_llvm_instrument_coverage_requires_llvm_12 =
-    rustc option `-C instrument-coverage` requires LLVM 12 or higher.
-
 codegen_llvm_symbol_already_defined =
     symbol `{$symbol_name}` is already defined
 
index 164d6d26d230d656f0896e69cf8269b9d8845aaa..bcc1d9002dfdebe040e00726a48a8a34dceac576 100644 (file)
@@ -147,8 +147,6 @@ infer_region_explanation = {$pref_kind ->
 }{$desc_kind ->
     *[should_not_happen] [{$desc_kind}]
     [restatic] the static lifetime
-    [reempty] the empty lifetime
-    [reemptyuni] the empty lifetime in universe {$desc_arg}
     [revar] lifetime {$desc_arg}
 
     [as_defined] the lifetime `{$desc_arg}` as defined here
index 224855fff8b56f35a7e02214a87749dd8cc89890..f9bda721df34dcb30830c092aa5dd918691c8b9b 100644 (file)
@@ -299,10 +299,18 @@ mir_build_borrow_of_moved_value = borrow of moved value
     .suggestion = borrow this binding in the pattern to avoid moving the value
 
 mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once at a time
-    .label = first mutable borrow, by `{$name}`, occurs here
-    .mutable_borrow = another mutable borrow, by `{$name_mut}`, occurs here
-    .immutable_borrow = also borrowed as immutable, by `{$name_immut}`, here
-    .moved = also moved into `{$name_moved}` here
+
+mir_build_already_borrowed = cannot borrow value as mutable because it is also borrowed as immutable
+
+mir_build_already_mut_borrowed = cannot borrow value as immutable because it is also borrowed as mutable
+
+mir_build_moved_while_borrowed = cannot move out of value because it is borrowed
+
+mir_build_mutable_borrow = value is mutably borrowed by `{$name}` here
+
+mir_build_borrow = value is borrowed by `{$name}` here
+
+mir_build_moved = value is moved into `{$name}` here
 
 mir_build_union_pattern = cannot use unions in constant patterns
 
index 91857dd227ddd602bb0eeee9eee8a291faa3ebbc..0c2ab3d08f9dea13d6b1da74a346e231f40c9f6f 100644 (file)
@@ -710,3 +710,24 @@ passes_ignored_derived_impls =
       [one] trait {$trait_list}, but this is
      *[other] traits {$trait_list}, but these are
     } intentionally ignored during dead code analysis
+
+passes_proc_macro_typeerror = mismatched {$kind} signature
+    .label = found {$found}, expected type `proc_macro::TokenStream`
+    .note = {$kind}s must have a signature of `{$expected_signature}`
+
+passes_proc_macro_diff_arg_count = mismatched {$kind} signature
+    .label = found unexpected {$count ->
+      [one] argument
+     *[other] arguments
+    }
+    .note = {$kind}s must have a signature of `{$expected_signature}`
+
+passes_proc_macro_missing_args = mismatched {$kind} signature
+    .label = {$kind} must have {$expected_input_count ->
+      [one] one argument
+     *[other] two arguments
+    } of type `proc_macro::TokenStream`
+
+passes_proc_macro_invalid_abi = proc macro functions may not be `extern "{$abi}"`
+
+passes_proc_macro_unsafe = proc macro functions may not be `unsafe`
index 37a51980a0888b375ff07b9b33fdca744c521337..f053bdc3809be30d5377cae4abc3960f503644b9 100644 (file)
@@ -182,6 +182,9 @@ pub fn fluent_bundle(
     trace!(?locale);
     let mut bundle = new_bundle(vec![locale]);
 
+    // Add convenience functions available to ftl authors.
+    register_functions(&mut bundle);
+
     // Fluent diagnostics can insert directionality isolation markers around interpolated variables
     // indicating that there may be a shift from right-to-left to left-to-right text (or
     // vice-versa). These are disabled because they are sometimes visible in the error output, but
@@ -244,6 +247,15 @@ pub fn fluent_bundle(
     Ok(Some(bundle))
 }
 
+fn register_functions(bundle: &mut FluentBundle) {
+    bundle
+        .add_function("STREQ", |positional, _named| match positional {
+            [FluentValue::String(a), FluentValue::String(b)] => format!("{}", (a == b)).into(),
+            _ => FluentValue::Error,
+        })
+        .expect("Failed to add a function to the bundle.");
+}
+
 /// Type alias for the result of `fallback_fluent_bundle` - a reference-counted pointer to a lazily
 /// evaluated fluent bundle.
 pub type LazyFallbackBundle = Lrc<Lazy<FluentBundle, impl FnOnce() -> FluentBundle>>;
@@ -256,6 +268,9 @@ pub fn fallback_fluent_bundle(
 ) -> LazyFallbackBundle {
     Lrc::new(Lazy::new(move || {
         let mut fallback_bundle = new_bundle(vec![langid!("en-US")]);
+
+        register_functions(&mut fallback_bundle);
+
         // See comment in `fluent_bundle`.
         fallback_bundle.set_use_isolating(with_directionality_markers);
 
index b456bd08048db153a3e8e10e95d940d2f11cedd5..5a620263e4299a2b51fb9f4c032196f22e597534 100644 (file)
@@ -2117,6 +2117,8 @@ pub enum MatchSource {
     TryDesugar,
     /// A desugared `<expr>.await`.
     AwaitDesugar,
+    /// A desugared `format_args!()`.
+    FormatArgs,
 }
 
 impl MatchSource {
@@ -2128,6 +2130,7 @@ pub const fn name(self) -> &'static str {
             ForLoopDesugar => "for",
             TryDesugar => "?",
             AwaitDesugar => ".await",
+            FormatArgs => "format_args!()",
         }
     }
 }
index 54fa5702fbca4b49298e49472722991f023a9751..9158fc082471f8fbedaf7e915fa998d83243215d 100644 (file)
@@ -244,6 +244,14 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
     /// libstd panic entry point. Necessary for const eval to be able to catch it
     BeginPanic,              sym::begin_panic,         begin_panic_fn,             Target::Fn,             GenericRequirement::None;
 
+    // Lang items needed for `format_args!()`.
+    FormatAlignment,         sym::format_alignment,    format_alignment,           Target::Enum,           GenericRequirement::None;
+    FormatArgument,          sym::format_argument,     format_argument,            Target::Struct,         GenericRequirement::None;
+    FormatArguments,         sym::format_arguments,    format_arguments,           Target::Struct,         GenericRequirement::None;
+    FormatCount,             sym::format_count,        format_count,               Target::Enum,           GenericRequirement::None;
+    FormatPlaceholder,       sym::format_placeholder,  format_placeholder,         Target::Struct,         GenericRequirement::None;
+    FormatUnsafeArg,         sym::format_unsafe_arg,   format_unsafe_arg,          Target::Struct,         GenericRequirement::None;
+
     ExchangeMalloc,          sym::exchange_malloc,     exchange_malloc_fn,         Target::Fn,             GenericRequirement::None;
     BoxFree,                 sym::box_free,            box_free_fn,                Target::Fn,             GenericRequirement::Minimum(1);
     DropInPlace,             sym::drop_in_place,       drop_in_place_fn,           Target::Fn,             GenericRequirement::Minimum(1);
index 7379e75963f532b5d6642b27d2b025b6cb739b30..a7b6a5c0331fc9722e126952c4198d309c27e86c 100644 (file)
@@ -62,7 +62,7 @@ pub fn emit_type_mismatch_suggestions(
             || self.suggest_floating_point_literal(err, expr, expected)
             || self.note_result_coercion(err, expr, expected, expr_ty);
         if !suggested {
-            self.point_at_expr_source_of_inferred_type(err, expr, expr_ty, expected);
+            self.point_at_expr_source_of_inferred_type(err, expr, expr_ty, expected, expr.span);
         }
     }
 
@@ -222,6 +222,7 @@ pub fn point_at_expr_source_of_inferred_type(
         expr: &hir::Expr<'_>,
         found: Ty<'tcx>,
         expected: Ty<'tcx>,
+        mismatch_span: Span,
     ) -> bool {
         let map = self.tcx.hir();
 
@@ -270,7 +271,7 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
             lt_op: |_| self.tcx.lifetimes.re_erased,
             ct_op: |c| c,
             ty_op: |t| match *t.kind() {
-                ty::Infer(ty::TyVar(vid)) => self.tcx.mk_ty_infer(ty::TyVar(self.root_var(vid))),
+                ty::Infer(ty::TyVar(_)) => self.tcx.mk_ty_var(ty::TyVid::from_u32(0)),
                 ty::Infer(ty::IntVar(_)) => {
                     self.tcx.mk_ty_infer(ty::IntVar(ty::IntVid { index: 0 }))
                 }
@@ -281,7 +282,7 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
             },
         };
         let mut prev = eraser.fold_ty(ty);
-        let mut prev_span = None;
+        let mut prev_span: Option<Span> = None;
 
         for binding in expr_finder.uses {
             // In every expression where the binding is referenced, we will look at that
@@ -333,13 +334,15 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
                             // inferred in this method call.
                             let arg = &args[i];
                             let arg_ty = self.node_ty(arg.hir_id);
-                            err.span_label(
-                                arg.span,
-                                &format!(
-                                    "this is of type `{arg_ty}`, which causes `{ident}` to be \
-                                     inferred as `{ty}`",
-                                ),
-                            );
+                            if !arg.span.overlaps(mismatch_span) {
+                                err.span_label(
+                                    arg.span,
+                                    &format!(
+                                        "this is of type `{arg_ty}`, which causes `{ident}` to be \
+                                        inferred as `{ty}`",
+                                    ),
+                                );
+                            }
                             param_args.insert(param_ty, (arg, arg_ty));
                         }
                     }
@@ -382,12 +385,13 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
                     && self.can_eq(self.param_env, ty, found).is_ok()
                 {
                     // We only point at the first place where the found type was inferred.
+                    if !segment.ident.span.overlaps(mismatch_span) {
                     err.span_label(
                         segment.ident.span,
                         with_forced_trimmed_paths!(format!(
                             "here the type of `{ident}` is inferred to be `{ty}`",
                         )),
-                    );
+                    );}
                     break;
                 } else if !param_args.is_empty() {
                     break;
@@ -406,12 +410,14 @@ fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
                     // We use the *previous* span because if the type is known *here* it means
                     // it was *evaluated earlier*. We don't do this for method calls because we
                     // evaluate the method's self type eagerly, but not in any other case.
-                    err.span_label(
-                        span,
-                        with_forced_trimmed_paths!(format!(
-                            "here the type of `{ident}` is inferred to be `{ty}`",
-                        )),
-                    );
+                    if !span.overlaps(mismatch_span) {
+                        err.span_label(
+                            span,
+                            with_forced_trimmed_paths!(format!(
+                                "here the type of `{ident}` is inferred to be `{ty}`",
+                            )),
+                        );
+                    }
                     break;
                 }
                 prev = ty;
index a6d96881c8f290efd9d014f521954cd448beca4e..e78c76d5dde7031337b15a34272520d5438cebff 100644 (file)
@@ -808,7 +808,13 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
                     kind: TypeVariableOriginKind::MiscVariable,
                     span: full_call_span,
                 });
-                self.point_at_expr_source_of_inferred_type(&mut err, rcvr, expected, callee_ty);
+                self.point_at_expr_source_of_inferred_type(
+                    &mut err,
+                    rcvr,
+                    expected,
+                    callee_ty,
+                    provided_arg_span,
+                );
             }
             // Call out where the function is defined
             self.label_fn_like(
index 3c873024c924f3837c473312fb3c0395be8eeaa1..2c76582f2ec8fbd14b9b911b4f922498a747b4d0 100644 (file)
@@ -38,6 +38,7 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) {
         let tcx = self.tcx;
+        let dl = &tcx.data_layout;
         let span = tcx.hir().span(hir_id);
         let normalize = |ty| {
             let ty = self.resolve_vars_if_possible(ty);
@@ -69,7 +70,7 @@ pub fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) {
             // Special-case transmuting from `typeof(function)` and
             // `Option<typeof(function)>` to present a clearer error.
             let from = unpack_option_like(tcx, from);
-            if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer.size(&tcx) {
+            if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer(dl.instruction_address_space).size(&tcx) {
                 struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type")
                     .note(&format!("source type: {from}"))
                     .note(&format!("target type: {to}"))
index 79704b6adf78e0e6b204d701d014664d2e7c513a..d19a0007f0880f7ac0f7083ea5cef9bbb23444dc 100644 (file)
@@ -79,6 +79,7 @@
 use std::{cmp, fmt, iter};
 
 mod note;
+mod note_and_explain;
 mod suggest;
 
 pub(crate) mod need_type_info;
@@ -1846,7 +1847,8 @@ enum Similar<'tcx> {
         }
 
         self.check_and_note_conflicting_crates(diag, terr);
-        self.tcx.note_and_explain_type_err(diag, terr, cause, span, cause.body_id.to_def_id());
+
+        self.note_and_explain_type_err(diag, terr, cause, span, cause.body_id.to_def_id());
 
         if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values
             && let ty::Closure(def_id, _) = exp_found.expected.skip_binder().self_ty().kind()
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
new file mode 100644 (file)
index 0000000..425cde3
--- /dev/null
@@ -0,0 +1,654 @@
+use super::TypeErrCtxt;
+use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
+use rustc_errors::{pluralize, Diagnostic, MultiSpan};
+use rustc_hir::{self as hir, def::DefKind};
+use rustc_middle::traits::ObligationCauseCode;
+use rustc_middle::ty::error::ExpectedFound;
+use rustc_middle::ty::print::Printer;
+use rustc_middle::{
+    traits::ObligationCause,
+    ty::{self, error::TypeError, print::FmtPrinter, suggest_constraining_type_param, Ty},
+};
+use rustc_span::{def_id::DefId, sym, BytePos, Span, Symbol};
+
+impl<'tcx> TypeErrCtxt<'_, 'tcx> {
+    pub fn note_and_explain_type_err(
+        &self,
+        diag: &mut Diagnostic,
+        err: TypeError<'tcx>,
+        cause: &ObligationCause<'tcx>,
+        sp: Span,
+        body_owner_def_id: DefId,
+    ) {
+        use ty::error::TypeError::*;
+        debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause);
+
+        let tcx = self.tcx;
+
+        match err {
+            ArgumentSorts(values, _) | Sorts(values) => {
+                match (values.expected.kind(), values.found.kind()) {
+                    (ty::Closure(..), ty::Closure(..)) => {
+                        diag.note("no two closures, even if identical, have the same type");
+                        diag.help("consider boxing your closure and/or using it as a trait object");
+                    }
+                    (ty::Alias(ty::Opaque, ..), ty::Alias(ty::Opaque, ..)) => {
+                        // Issue #63167
+                        diag.note("distinct uses of `impl Trait` result in different opaque types");
+                    }
+                    (ty::Float(_), ty::Infer(ty::IntVar(_)))
+                        if let Ok(
+                            // Issue #53280
+                            snippet,
+                        ) = tcx.sess.source_map().span_to_snippet(sp) =>
+                    {
+                        if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') {
+                            diag.span_suggestion(
+                                sp,
+                                "use a float literal",
+                                format!("{}.0", snippet),
+                                MachineApplicable,
+                            );
+                        }
+                    }
+                    (ty::Param(expected), ty::Param(found)) => {
+                        let generics = tcx.generics_of(body_owner_def_id);
+                        let e_span = tcx.def_span(generics.type_param(expected, tcx).def_id);
+                        if !sp.contains(e_span) {
+                            diag.span_label(e_span, "expected type parameter");
+                        }
+                        let f_span = tcx.def_span(generics.type_param(found, tcx).def_id);
+                        if !sp.contains(f_span) {
+                            diag.span_label(f_span, "found type parameter");
+                        }
+                        diag.note(
+                            "a type parameter was expected, but a different one was found; \
+                             you might be missing a type parameter or trait bound",
+                        );
+                        diag.note(
+                            "for more information, visit \
+                             https://doc.rust-lang.org/book/ch10-02-traits.html\
+                             #traits-as-parameters",
+                        );
+                    }
+                    (ty::Alias(ty::Projection, _), ty::Alias(ty::Projection, _)) => {
+                        diag.note("an associated type was expected, but a different one was found");
+                    }
+                    (ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
+                        if tcx.def_kind(proj.def_id) != DefKind::ImplTraitPlaceholder =>
+                    {
+                        let generics = tcx.generics_of(body_owner_def_id);
+                        let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
+                        if !sp.contains(p_span) {
+                            diag.span_label(p_span, "this type parameter");
+                        }
+                        let hir = tcx.hir();
+                        let mut note = true;
+                        if let Some(generics) = generics
+                            .type_param(p, tcx)
+                            .def_id
+                            .as_local()
+                            .map(|id| hir.local_def_id_to_hir_id(id))
+                            .and_then(|id| tcx.hir().find_parent(id))
+                            .as_ref()
+                            .and_then(|node| node.generics())
+                        {
+                            // Synthesize the associated type restriction `Add<Output = Expected>`.
+                            // FIXME: extract this logic for use in other diagnostics.
+                            let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(tcx);
+                            let path =
+                                tcx.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs);
+                            let item_name = tcx.item_name(proj.def_id);
+                            let item_args = self.format_generic_args(assoc_substs);
+
+                            let path = if path.ends_with('>') {
+                                format!(
+                                    "{}, {}{} = {}>",
+                                    &path[..path.len() - 1],
+                                    item_name,
+                                    item_args,
+                                    p
+                                )
+                            } else {
+                                format!("{}<{}{} = {}>", path, item_name, item_args, p)
+                            };
+                            note = !suggest_constraining_type_param(
+                                tcx,
+                                generics,
+                                diag,
+                                &format!("{}", proj.self_ty()),
+                                &path,
+                                None,
+                            );
+                        }
+                        if note {
+                            diag.note("you might be missing a type parameter or trait bound");
+                        }
+                    }
+                    (ty::Param(p), ty::Dynamic(..) | ty::Alias(ty::Opaque, ..))
+                    | (ty::Dynamic(..) | ty::Alias(ty::Opaque, ..), ty::Param(p)) => {
+                        let generics = tcx.generics_of(body_owner_def_id);
+                        let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
+                        if !sp.contains(p_span) {
+                            diag.span_label(p_span, "this type parameter");
+                        }
+                        diag.help("type parameters must be constrained to match other types");
+                        if tcx.sess.teach(&diag.get_code().unwrap()) {
+                            diag.help(
+                                "given a type parameter `T` and a method `foo`:
+```
+trait Trait<T> { fn foo(&tcx) -> T; }
+```
+the only ways to implement method `foo` are:
+- constrain `T` with an explicit type:
+```
+impl Trait<String> for X {
+    fn foo(&tcx) -> String { String::new() }
+}
+```
+- add a trait bound to `T` and call a method on that trait that returns `Self`:
+```
+impl<T: std::default::Default> Trait<T> for X {
+    fn foo(&tcx) -> T { <T as std::default::Default>::default() }
+}
+```
+- change `foo` to return an argument of type `T`:
+```
+impl<T> Trait<T> for X {
+    fn foo(&tcx, x: T) -> T { x }
+}
+```",
+                            );
+                        }
+                        diag.note(
+                            "for more information, visit \
+                             https://doc.rust-lang.org/book/ch10-02-traits.html\
+                             #traits-as-parameters",
+                        );
+                    }
+                    (ty::Param(p), ty::Closure(..) | ty::Generator(..)) => {
+                        let generics = tcx.generics_of(body_owner_def_id);
+                        let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
+                        if !sp.contains(p_span) {
+                            diag.span_label(p_span, "this type parameter");
+                        }
+                        diag.help(&format!(
+                            "every closure has a distinct type and so could not always match the \
+                             caller-chosen type of parameter `{}`",
+                            p
+                        ));
+                    }
+                    (ty::Param(p), _) | (_, ty::Param(p)) => {
+                        let generics = tcx.generics_of(body_owner_def_id);
+                        let p_span = tcx.def_span(generics.type_param(p, tcx).def_id);
+                        if !sp.contains(p_span) {
+                            diag.span_label(p_span, "this type parameter");
+                        }
+                    }
+                    (ty::Alias(ty::Projection, proj_ty), _) if tcx.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => {
+                        self.expected_projection(
+                            diag,
+                            proj_ty,
+                            values,
+                            body_owner_def_id,
+                            cause.code(),
+                        );
+                    }
+                    (_, ty::Alias(ty::Projection, proj_ty)) if tcx.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => {
+                        let msg = format!(
+                            "consider constraining the associated type `{}` to `{}`",
+                            values.found, values.expected,
+                        );
+                        if !(self.suggest_constraining_opaque_associated_type(
+                            diag,
+                            &msg,
+                            proj_ty,
+                            values.expected,
+                        ) || self.suggest_constraint(
+                            diag,
+                            &msg,
+                            body_owner_def_id,
+                            proj_ty,
+                            values.expected,
+                        )) {
+                            diag.help(&msg);
+                            diag.note(
+                                "for more information, visit \
+                                https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
+                            );
+                        }
+                    }
+                    _ => {}
+                }
+                debug!(
+                    "note_and_explain_type_err expected={:?} ({:?}) found={:?} ({:?})",
+                    values.expected,
+                    values.expected.kind(),
+                    values.found,
+                    values.found.kind(),
+                );
+            }
+            CyclicTy(ty) => {
+                // Watch out for various cases of cyclic types and try to explain.
+                if ty.is_closure() || ty.is_generator() {
+                    diag.note(
+                        "closures cannot capture themselves or take themselves as argument;\n\
+                         this error may be the result of a recent compiler bug-fix,\n\
+                         see issue #46062 <https://github.com/rust-lang/rust/issues/46062>\n\
+                         for more information",
+                    );
+                }
+            }
+            TargetFeatureCast(def_id) => {
+                let target_spans = tcx.get_attrs(def_id, sym::target_feature).map(|attr| attr.span);
+                diag.note(
+                    "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers"
+                );
+                diag.span_labels(target_spans, "`#[target_feature]` added here");
+            }
+            _ => {}
+        }
+    }
+
+    fn suggest_constraint(
+        &self,
+        diag: &mut Diagnostic,
+        msg: &str,
+        body_owner_def_id: DefId,
+        proj_ty: &ty::AliasTy<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> bool {
+        let tcx = self.tcx;
+        let assoc = tcx.associated_item(proj_ty.def_id);
+        let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(tcx);
+        if let Some(item) = tcx.hir().get_if_local(body_owner_def_id) {
+            if let Some(hir_generics) = item.generics() {
+                // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
+                // This will also work for `impl Trait`.
+                let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind() {
+                    let generics = tcx.generics_of(body_owner_def_id);
+                    generics.type_param(param_ty, tcx).def_id
+                } else {
+                    return false;
+                };
+                let Some(def_id) = def_id.as_local() else {
+                    return false;
+                };
+
+                // First look in the `where` clause, as this might be
+                // `fn foo<T>(x: T) where T: Trait`.
+                for pred in hir_generics.bounds_for_param(def_id) {
+                    if self.constrain_generic_bound_associated_type_structured_suggestion(
+                        diag,
+                        &trait_ref,
+                        pred.bounds,
+                        &assoc,
+                        assoc_substs,
+                        ty,
+                        msg,
+                        false,
+                    ) {
+                        return true;
+                    }
+                }
+            }
+        }
+        false
+    }
+
+    /// An associated type was expected and a different type was found.
+    ///
+    /// We perform a few different checks to see what we can suggest:
+    ///
+    ///  - In the current item, look for associated functions that return the expected type and
+    ///    suggest calling them. (Not a structured suggestion.)
+    ///  - If any of the item's generic bounds can be constrained, we suggest constraining the
+    ///    associated type to the found type.
+    ///  - If the associated type has a default type and was expected inside of a `trait`, we
+    ///    mention that this is disallowed.
+    ///  - If all other things fail, and the error is not because of a mismatch between the `trait`
+    ///    and the `impl`, we provide a generic `help` to constrain the assoc type or call an assoc
+    ///    fn that returns the type.
+    fn expected_projection(
+        &self,
+        diag: &mut Diagnostic,
+        proj_ty: &ty::AliasTy<'tcx>,
+        values: ExpectedFound<Ty<'tcx>>,
+        body_owner_def_id: DefId,
+        cause_code: &ObligationCauseCode<'_>,
+    ) {
+        let tcx = self.tcx;
+
+        let msg = format!(
+            "consider constraining the associated type `{}` to `{}`",
+            values.expected, values.found
+        );
+        let body_owner = tcx.hir().get_if_local(body_owner_def_id);
+        let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name);
+
+        // We don't want to suggest calling an assoc fn in a scope where that isn't feasible.
+        let callable_scope = matches!(
+            body_owner,
+            Some(
+                hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })
+                    | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
+                    | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }),
+            )
+        );
+        let impl_comparison =
+            matches!(cause_code, ObligationCauseCode::CompareImplItemObligation { .. });
+        let assoc = tcx.associated_item(proj_ty.def_id);
+        if !callable_scope || impl_comparison {
+            // We do not want to suggest calling functions when the reason of the
+            // type error is a comparison of an `impl` with its `trait` or when the
+            // scope is outside of a `Body`.
+        } else {
+            // If we find a suitable associated function that returns the expected type, we don't
+            // want the more general suggestion later in this method about "consider constraining
+            // the associated type or calling a method that returns the associated type".
+            let point_at_assoc_fn = self.point_at_methods_that_satisfy_associated_type(
+                diag,
+                assoc.container_id(tcx),
+                current_method_ident,
+                proj_ty.def_id,
+                values.expected,
+            );
+            // Possibly suggest constraining the associated type to conform to the
+            // found type.
+            if self.suggest_constraint(diag, &msg, body_owner_def_id, proj_ty, values.found)
+                || point_at_assoc_fn
+            {
+                return;
+            }
+        }
+
+        self.suggest_constraining_opaque_associated_type(diag, &msg, proj_ty, values.found);
+
+        if self.point_at_associated_type(diag, body_owner_def_id, values.found) {
+            return;
+        }
+
+        if !impl_comparison {
+            // Generic suggestion when we can't be more specific.
+            if callable_scope {
+                diag.help(&format!(
+                    "{} or calling a method that returns `{}`",
+                    msg, values.expected
+                ));
+            } else {
+                diag.help(&msg);
+            }
+            diag.note(
+                "for more information, visit \
+                 https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
+            );
+        }
+        if tcx.sess.teach(&diag.get_code().unwrap()) {
+            diag.help(
+                "given an associated type `T` and a method `foo`:
+```
+trait Trait {
+type T;
+fn foo(&tcx) -> Self::T;
+}
+```
+the only way of implementing method `foo` is to constrain `T` with an explicit associated type:
+```
+impl Trait for X {
+type T = String;
+fn foo(&tcx) -> Self::T { String::new() }
+}
+```",
+            );
+        }
+    }
+
+    /// When the expected `impl Trait` is not defined in the current item, it will come from
+    /// a return type. This can occur when dealing with `TryStream` (#71035).
+    fn suggest_constraining_opaque_associated_type(
+        &self,
+        diag: &mut Diagnostic,
+        msg: &str,
+        proj_ty: &ty::AliasTy<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> bool {
+        let tcx = self.tcx;
+
+        let assoc = tcx.associated_item(proj_ty.def_id);
+        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 &tcx.hir().expect_item(opaque_local_def_id).kind {
+                    hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
+                    _ => bug!("The HirId comes from a `ty::Opaque`"),
+                }
+            } else {
+                return false;
+            };
+
+            let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(tcx);
+
+            self.constrain_generic_bound_associated_type_structured_suggestion(
+                diag,
+                &trait_ref,
+                opaque_hir_ty.bounds,
+                assoc,
+                assoc_substs,
+                ty,
+                msg,
+                true,
+            )
+        } else {
+            false
+        }
+    }
+
+    fn point_at_methods_that_satisfy_associated_type(
+        &self,
+        diag: &mut Diagnostic,
+        assoc_container_id: DefId,
+        current_method_ident: Option<Symbol>,
+        proj_ty_item_def_id: DefId,
+        expected: Ty<'tcx>,
+    ) -> bool {
+        let tcx = self.tcx;
+
+        let items = tcx.associated_items(assoc_container_id);
+        // Find all the methods in the trait that could be called to construct the
+        // expected associated type.
+        // FIXME: consider suggesting the use of associated `const`s.
+        let methods: Vec<(Span, String)> = items
+            .in_definition_order()
+            .filter(|item| {
+                ty::AssocKind::Fn == item.kind && Some(item.name) != current_method_ident
+            })
+            .filter_map(|item| {
+                let method = tcx.fn_sig(item.def_id);
+                match *method.output().skip_binder().kind() {
+                    ty::Alias(ty::Projection, ty::AliasTy { def_id: item_def_id, .. })
+                        if item_def_id == proj_ty_item_def_id =>
+                    {
+                        Some((
+                            tcx.def_span(item.def_id),
+                            format!("consider calling `{}`", tcx.def_path_str(item.def_id)),
+                        ))
+                    }
+                    _ => None,
+                }
+            })
+            .collect();
+        if !methods.is_empty() {
+            // Use a single `help:` to show all the methods in the trait that can
+            // be used to construct the expected associated type.
+            let mut span: MultiSpan =
+                methods.iter().map(|(sp, _)| *sp).collect::<Vec<Span>>().into();
+            let msg = format!(
+                "{some} method{s} {are} available that return{r} `{ty}`",
+                some = if methods.len() == 1 { "a" } else { "some" },
+                s = pluralize!(methods.len()),
+                are = pluralize!("is", methods.len()),
+                r = if methods.len() == 1 { "s" } else { "" },
+                ty = expected
+            );
+            for (sp, label) in methods.into_iter() {
+                span.push_span_label(sp, label);
+            }
+            diag.span_help(span, &msg);
+            return true;
+        }
+        false
+    }
+
+    fn point_at_associated_type(
+        &self,
+        diag: &mut Diagnostic,
+        body_owner_def_id: DefId,
+        found: Ty<'tcx>,
+    ) -> bool {
+        let tcx = self.tcx;
+
+        let Some(hir_id) = body_owner_def_id.as_local() else {
+            return false;
+        };
+        let hir_id = tcx.hir().local_def_id_to_hir_id(hir_id);
+        // When `body_owner` is an `impl` or `trait` item, look in its associated types for
+        // `expected` and point at it.
+        let parent_id = tcx.hir().get_parent_item(hir_id);
+        let item = tcx.hir().find_by_def_id(parent_id.def_id);
+
+        debug!("expected_projection parent item {:?}", item);
+
+        let param_env = tcx.param_env(body_owner_def_id);
+
+        match item {
+            Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. })) => {
+                // FIXME: account for `#![feature(specialization)]`
+                for item in &items[..] {
+                    match item.kind {
+                        hir::AssocItemKind::Type => {
+                            // FIXME: account for returning some type in a trait fn impl that has
+                            // an assoc type as a return type (#72076).
+                            if let hir::Defaultness::Default { has_value: true } =
+                                tcx.impl_defaultness(item.id.owner_id)
+                            {
+                                let assoc_ty = tcx.bound_type_of(item.id.owner_id).subst_identity();
+                                if self.infcx.can_eq(param_env, assoc_ty, found).is_ok() {
+                                    diag.span_label(
+                                        item.span,
+                                        "associated type defaults can't be assumed inside the \
+                                            trait defining them",
+                                    );
+                                    return true;
+                                }
+                            }
+                        }
+                        _ => {}
+                    }
+                }
+            }
+            Some(hir::Node::Item(hir::Item {
+                kind: hir::ItemKind::Impl(hir::Impl { items, .. }),
+                ..
+            })) => {
+                for item in &items[..] {
+                    if let hir::AssocItemKind::Type = item.kind {
+                        let assoc_ty = tcx.bound_type_of(item.id.owner_id).subst_identity();
+
+                        if self.infcx.can_eq(param_env, assoc_ty, found).is_ok() {
+                            diag.span_label(item.span, "expected this associated type");
+                            return true;
+                        }
+                    }
+                }
+            }
+            _ => {}
+        }
+        false
+    }
+
+    /// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref`
+    /// requirement, provide a structured suggestion to constrain it to a given type `ty`.
+    ///
+    /// `is_bound_surely_present` indicates whether we know the bound we're looking for is
+    /// inside `bounds`. If that's the case then we can consider `bounds` containing only one
+    /// trait bound as the one we're looking for. This can help in cases where the associated
+    /// type is defined on a supertrait of the one present in the bounds.
+    fn constrain_generic_bound_associated_type_structured_suggestion(
+        &self,
+        diag: &mut Diagnostic,
+        trait_ref: &ty::TraitRef<'tcx>,
+        bounds: hir::GenericBounds<'_>,
+        assoc: &ty::AssocItem,
+        assoc_substs: &[ty::GenericArg<'tcx>],
+        ty: Ty<'tcx>,
+        msg: &str,
+        is_bound_surely_present: bool,
+    ) -> bool {
+        // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting.
+
+        let trait_bounds = bounds.iter().filter_map(|bound| match bound {
+            hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => Some(ptr),
+            _ => None,
+        });
+
+        let matching_trait_bounds = trait_bounds
+            .clone()
+            .filter(|ptr| ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id))
+            .collect::<Vec<_>>();
+
+        let span = match &matching_trait_bounds[..] {
+            &[ptr] => ptr.span,
+            &[] if is_bound_surely_present => match &trait_bounds.collect::<Vec<_>>()[..] {
+                &[ptr] => ptr.span,
+                _ => return false,
+            },
+            _ => return false,
+        };
+
+        self.constrain_associated_type_structured_suggestion(
+            diag,
+            span,
+            assoc,
+            assoc_substs,
+            ty,
+            msg,
+        )
+    }
+
+    /// Given a span corresponding to a bound, provide a structured suggestion to set an
+    /// associated type to a given type `ty`.
+    fn constrain_associated_type_structured_suggestion(
+        &self,
+        diag: &mut Diagnostic,
+        span: Span,
+        assoc: &ty::AssocItem,
+        assoc_substs: &[ty::GenericArg<'tcx>],
+        ty: Ty<'tcx>,
+        msg: &str,
+    ) -> bool {
+        let tcx = self.tcx;
+
+        if let Ok(has_params) =
+            tcx.sess.source_map().span_to_snippet(span).map(|snippet| snippet.ends_with('>'))
+        {
+            let (span, sugg) = if has_params {
+                let pos = span.hi() - BytePos(1);
+                let span = Span::new(pos, pos, span.ctxt(), span.parent());
+                (span, format!(", {} = {}", assoc.ident(tcx), ty))
+            } else {
+                let item_args = self.format_generic_args(assoc_substs);
+                (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident(tcx), item_args, ty))
+            };
+            diag.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
+            return true;
+        }
+        false
+    }
+
+    pub fn format_generic_args(&self, args: &[ty::GenericArg<'tcx>]) -> String {
+        FmtPrinter::new(self.tcx, hir::def::Namespace::TypeNS)
+            .path_generic_args(Ok, args)
+            .expect("could not write to `String`.")
+            .into_buffer()
+    }
+}
index eb7bd7256c6747288b2eb4f28c762c2066a1c074..768cef89f3c439b2c61092d4bdcfa7a65ea5151b 100644 (file)
@@ -380,7 +380,7 @@ pub(super) fn suggest_function_pointers(
                     return;
                 }
 
-                let (msg, sugg) = match (expected.is_ref(), found.is_ref()) {
+                let (msg, sug) = match (expected.is_ref(), found.is_ref()) {
                     (true, false) => {
                         let msg = "consider using a reference";
                         let sug = format!("&{fn_name}");
@@ -404,7 +404,7 @@ pub(super) fn suggest_function_pointers(
                         (msg, sug)
                     }
                 };
-                diag.span_suggestion(span, msg, &sugg, Applicability::MaybeIncorrect);
+                diag.span_suggestion(span, msg, sug, Applicability::MaybeIncorrect);
             }
             (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => {
                 let expected_sig =
@@ -412,14 +412,50 @@ pub(super) fn suggest_function_pointers(
                 let found_sig =
                     &(self.normalize_fn_sig)(self.tcx.bound_fn_sig(*did2).subst(self.tcx, substs2));
 
-                if self.same_type_modulo_infer(*found_sig, *expected_sig) {
-                    diag.note(
-                    "different fn items have unique types, even if their signatures are the same",
-                    );
+                if self.same_type_modulo_infer(*expected_sig, *found_sig) {
+                    diag.note("different fn items have unique types, even if their signatures are the same");
+                }
+
+                if !self.same_type_modulo_infer(*found_sig, *expected_sig)
+                    || !found_sig.is_suggestable(self.tcx, true)
+                    || !expected_sig.is_suggestable(self.tcx, true)
+                    || ty::util::is_intrinsic(self.tcx, *did1)
+                    || ty::util::is_intrinsic(self.tcx, *did2)
+                {
+                    return;
                 }
+
+                let fn_name = self.tcx.def_path_str_with_substs(*did2, substs2);
+                let sug = if found.is_ref() {
+                    format!("&({fn_name} as {found_sig})")
+                } else {
+                    format!("{fn_name} as {found_sig}")
+                };
+
+                let msg = format!(
+                    "consider casting both fn items to fn pointers using `as {expected_sig}`"
+                );
+
+                diag.span_suggestion_hidden(span, msg, sug, Applicability::MaybeIncorrect);
             }
-            (ty::FnDef(_, _), ty::FnPtr(_)) => {
-                diag.note("fn items are distinct from fn pointers");
+            (ty::FnDef(did, substs), ty::FnPtr(sig)) => {
+                let expected_sig =
+                    &(self.normalize_fn_sig)(self.tcx.bound_fn_sig(*did).subst(self.tcx, substs));
+                let found_sig = &(self.normalize_fn_sig)(*sig);
+
+                if !self.same_type_modulo_infer(*found_sig, *expected_sig) {
+                    return;
+                }
+
+                let fn_name = self.tcx.def_path_str_with_substs(*did, substs);
+
+                let casting = if expected.is_ref() {
+                    format!("&({fn_name} as {found_sig})")
+                } else {
+                    format!("{fn_name} as {found_sig}")
+                };
+
+                diag.help(&format!("consider casting the fn item to a fn pointer: `{}`", casting));
             }
             _ => {
                 return;
index 379a76528f3bbba1d92aa19af21d0f15d8752d9d..37b381c534ea065c3a41e6ef3c4b2dd8d43ee225 100644 (file)
@@ -16,7 +16,7 @@
 use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
 use rustc_errors::{ErrorGuaranteed, PResult};
 use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand};
-use rustc_hir::def_id::StableCrateId;
+use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
 use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore};
 use rustc_metadata::creader::CStore;
 use rustc_middle::arena::Arena;
@@ -30,7 +30,7 @@
 use rustc_query_impl::{OnDiskCache, Queries as TcxQueries};
 use rustc_resolve::{Resolver, ResolverArenas};
 use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType};
-use rustc_session::cstore::{MetadataLoader, MetadataLoaderDyn, Untracked};
+use rustc_session::cstore::{CrateStoreDyn, MetadataLoader, MetadataLoaderDyn, Untracked};
 use rustc_session::output::filename_for_input;
 use rustc_session::search_paths::PathKind;
 use rustc_session::{Limit, Session};
@@ -47,7 +47,7 @@
 use std::path::{Path, PathBuf};
 use std::pin::Pin;
 use std::rc::Rc;
-use std::sync::LazyLock;
+use std::sync::{Arc, LazyLock};
 use std::{env, fs, iter};
 
 pub fn parse<'a>(sess: &'a Session) -> PResult<'a, ast::Crate> {
@@ -548,7 +548,7 @@ fn escape_dep_env(symbol: Symbol) -> String {
 
 fn write_out_deps(
     sess: &Session,
-    boxed_resolver: &RefCell<BoxedResolver>,
+    cstore: &CrateStoreDyn,
     outputs: &OutputFilenames,
     out_filenames: &[PathBuf],
 ) {
@@ -600,20 +600,19 @@ fn write_out_deps(
                 }
             }
 
-            boxed_resolver.borrow_mut().access(|resolver| {
-                for cnum in resolver.cstore().crates_untracked() {
-                    let source = resolver.cstore().crate_source_untracked(cnum);
-                    if let Some((path, _)) = &source.dylib {
-                        files.push(escape_dep_filename(&path.display().to_string()));
-                    }
-                    if let Some((path, _)) = &source.rlib {
-                        files.push(escape_dep_filename(&path.display().to_string()));
-                    }
-                    if let Some((path, _)) = &source.rmeta {
-                        files.push(escape_dep_filename(&path.display().to_string()));
-                    }
+            let cstore = cstore.as_any().downcast_ref::<CStore>().unwrap();
+            for cnum in cstore.crates_untracked() {
+                let source = cstore.crate_source_untracked(cnum);
+                if let Some((path, _)) = &source.dylib {
+                    files.push(escape_dep_filename(&path.display().to_string()));
                 }
-            });
+                if let Some((path, _)) = &source.rlib {
+                    files.push(escape_dep_filename(&path.display().to_string()));
+                }
+                if let Some((path, _)) = &source.rmeta {
+                    files.push(escape_dep_filename(&path.display().to_string()));
+                }
+            }
         }
 
         let mut file = BufWriter::new(fs::File::create(&deps_filename)?);
@@ -661,13 +660,11 @@ fn write_out_deps(
     }
 }
 
-pub fn prepare_outputs(
-    sess: &Session,
-    krate: &ast::Crate,
-    boxed_resolver: &RefCell<BoxedResolver>,
-    crate_name: Symbol,
-) -> Result<OutputFilenames> {
+fn output_filenames(tcx: TyCtxt<'_>, (): ()) -> Arc<OutputFilenames> {
+    let sess = tcx.sess;
     let _timer = sess.timer("prepare_outputs");
+    let (_, krate) = &*tcx.resolver_for_lowering(()).borrow();
+    let crate_name = tcx.crate_name(LOCAL_CRATE);
 
     // FIXME: rustdoc passes &[] instead of &krate.attrs here
     let outputs = util::build_output_filenames(&krate.attrs, sess);
@@ -679,25 +676,21 @@ pub fn prepare_outputs(
     if let Some(ref input_path) = sess.io.input.opt_path() {
         if sess.opts.will_create_output_file() {
             if output_contains_path(&output_paths, input_path) {
-                let reported = sess.emit_err(InputFileWouldBeOverWritten { path: input_path });
-                return Err(reported);
+                sess.emit_fatal(InputFileWouldBeOverWritten { path: input_path });
             }
             if let Some(ref dir_path) = output_conflicts_with_dir(&output_paths) {
-                let reported =
-                    sess.emit_err(GeneratedFileConflictsWithDirectory { input_path, dir_path });
-                return Err(reported);
+                sess.emit_fatal(GeneratedFileConflictsWithDirectory { input_path, dir_path });
             }
         }
     }
 
     if let Some(ref dir) = sess.io.temps_dir {
         if fs::create_dir_all(dir).is_err() {
-            let reported = sess.emit_err(TempsDirError);
-            return Err(reported);
+            sess.emit_fatal(TempsDirError);
         }
     }
 
-    write_out_deps(sess, boxed_resolver, &outputs, &output_paths);
+    write_out_deps(sess, tcx.cstore_untracked(), &outputs, &output_paths);
 
     let only_dep_info = sess.opts.output_types.contains_key(&OutputType::DepInfo)
         && sess.opts.output_types.len() == 1;
@@ -705,19 +698,19 @@ pub fn prepare_outputs(
     if !only_dep_info {
         if let Some(ref dir) = sess.io.output_dir {
             if fs::create_dir_all(dir).is_err() {
-                let reported = sess.emit_err(OutDirError);
-                return Err(reported);
+                sess.emit_fatal(OutDirError);
             }
         }
     }
 
-    Ok(outputs)
+    outputs.into()
 }
 
 pub static DEFAULT_QUERY_PROVIDERS: LazyLock<Providers> = LazyLock::new(|| {
     let providers = &mut Providers::default();
     providers.analysis = analysis;
     providers.hir_crate = rustc_ast_lowering::lower_to_hir;
+    providers.output_filenames = output_filenames;
     proc_macro_decls::provide(providers);
     rustc_const_eval::provide(providers);
     rustc_middle::hir::provide(providers);
index d5a49dd75be6a06bf7a7efa310342a139c15335b..4b0180741c19df0af11d84b6c6d388bc5b1ffc42 100644 (file)
@@ -65,7 +65,7 @@ fn deref_mut(&mut self) -> &mut Self::Target {
 }
 
 impl<'a, 'tcx> QueryResult<'a, QueryContext<'tcx>> {
-    pub fn enter<T>(mut self, f: impl FnOnce(TyCtxt<'tcx>) -> T) -> T {
+    pub fn enter<T>(&mut self, f: impl FnOnce(TyCtxt<'tcx>) -> T) -> T {
         (*self.0).get_mut().enter(f)
     }
 }
@@ -212,8 +212,6 @@ pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, QueryContext<'tcx>>> {
             let crate_name = *self.crate_name()?.borrow();
             let (krate, resolver, lint_store) = self.expansion()?.steal();
 
-            let outputs = passes::prepare_outputs(self.session(), &krate, &resolver, crate_name)?;
-
             let ty::ResolverOutputs {
                 untracked,
                 global_ctxt: untracked_resolutions,
@@ -237,7 +235,6 @@ pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, QueryContext<'tcx>>> {
                     tcx.arena.alloc(Steal::new((untracked_resolver_for_lowering, krate))),
                 );
                 feed.resolutions(tcx.arena.alloc(untracked_resolutions));
-                feed.output_filenames(tcx.arena.alloc(std::sync::Arc::new(outputs)));
                 feed.features_query(tcx.sess.features_untracked());
                 let feed = tcx.feed_local_crate();
                 feed.crate_name(crate_name);
index eebc2f21dfe4e8e4a79cc888f0aa41c8147d335e..e5d0bb87edf66f4baffbff184a50c95aac40d3d5 100644 (file)
@@ -632,6 +632,12 @@ pub fn may_have_doc_links_untracked(&self, def_id: DefId) -> bool {
             .get_attr_flags(def_id.index)
             .contains(AttrFlags::MAY_HAVE_DOC_LINKS)
     }
+
+    pub fn is_doc_hidden_untracked(&self, def_id: DefId) -> bool {
+        self.get_crate_data(def_id.krate)
+            .get_attr_flags(def_id.index)
+            .contains(AttrFlags::IS_DOC_HIDDEN)
+    }
 }
 
 impl CrateStore for CStore {
index 97f0457ba711677e0ea326bb1d099460da3672b9..d57eaf92d0fc68e79feb68f043b356294d61c3c3 100644 (file)
@@ -3,6 +3,7 @@
 use crate::rmeta::table::TableBuilder;
 use crate::rmeta::*;
 
+use rustc_ast::util::comments;
 use rustc_ast::Attribute;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
@@ -38,7 +39,6 @@
 use rustc_span::{
     self, DebuggerVisualizerFile, ExternalSource, FileName, SourceFile, Span, SyntaxContext,
 };
-use rustc_target::abi::VariantIdx;
 use std::borrow::Borrow;
 use std::collections::hash_map::Entry;
 use std::hash::Hash;
@@ -760,36 +760,54 @@ macro_rules! stat {
     }
 }
 
+struct AnalyzeAttrState {
+    is_exported: bool,
+    may_have_doc_links: bool,
+    is_doc_hidden: bool,
+}
+
 /// Returns whether an attribute needs to be recorded in metadata, that is, if it's usable and
 /// useful in downstream crates. Local-only attributes are an obvious example, but some
 /// rustdoc-specific attributes can equally be of use while documenting the current crate only.
 ///
 /// Removing these superfluous attributes speeds up compilation by making the metadata smaller.
 ///
-/// Note: the `is_def_id_public` parameter is used to cache whether the given `DefId` has a public
+/// Note: the `is_exported` parameter is used to cache whether the given `DefId` has a public
 /// visibility: this is a piece of data that can be computed once per defid, and not once per
 /// attribute. Some attributes would only be usable downstream if they are public.
 #[inline]
-fn should_encode_attr(
-    tcx: TyCtxt<'_>,
-    attr: &Attribute,
-    def_id: LocalDefId,
-    is_def_id_public: &mut Option<bool>,
-) -> bool {
+fn analyze_attr(attr: &Attribute, state: &mut AnalyzeAttrState) -> bool {
+    let mut should_encode = false;
     if rustc_feature::is_builtin_only_local(attr.name_or_empty()) {
         // Attributes marked local-only don't need to be encoded for downstream crates.
-        false
-    } else if attr.doc_str().is_some() {
-        // We keep all public doc comments because they might be "imported" into downstream crates
-        // if they use `#[doc(inline)]` to copy an item's documentation into their own.
-        *is_def_id_public.get_or_insert_with(|| tcx.effective_visibilities(()).is_exported(def_id))
+    } else if let Some(s) = attr.doc_str() {
+        // We keep all doc comments reachable to rustdoc because they might be "imported" into
+        // downstream crates if they use `#[doc(inline)]` to copy an item's documentation into
+        // their own.
+        if state.is_exported {
+            should_encode = true;
+            if comments::may_have_doc_links(s.as_str()) {
+                state.may_have_doc_links = true;
+            }
+        }
     } else if attr.has_name(sym::doc) {
-        // If this is a `doc` attribute, and it's marked `inline` (as in `#[doc(inline)]`), we can
-        // remove it. It won't be inlinable in downstream crates.
-        attr.meta_item_list().map(|l| l.iter().any(|l| !l.has_name(sym::inline))).unwrap_or(false)
+        // If this is a `doc` attribute that doesn't have anything except maybe `inline` (as in
+        // `#[doc(inline)]`), then we can remove it. It won't be inlinable in downstream crates.
+        if let Some(item_list) = attr.meta_item_list() {
+            for item in item_list {
+                if !item.has_name(sym::inline) {
+                    should_encode = true;
+                    if item.has_name(sym::hidden) {
+                        state.is_doc_hidden = true;
+                        break;
+                    }
+                }
+            }
+        }
     } else {
-        true
+        should_encode = true;
     }
+    should_encode
 }
 
 fn should_encode_visibility(def_kind: DefKind) -> bool {
@@ -1109,24 +1127,24 @@ fn should_encode_trait_impl_trait_tys(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
 impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
     fn encode_attrs(&mut self, def_id: LocalDefId) {
         let tcx = self.tcx;
-        let mut is_public: Option<bool> = None;
-
-        let hir_attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(def_id));
-        let mut attrs = hir_attrs
+        let mut state = AnalyzeAttrState {
+            is_exported: tcx.effective_visibilities(()).is_exported(def_id),
+            may_have_doc_links: false,
+            is_doc_hidden: false,
+        };
+        let attr_iter = tcx
+            .hir()
+            .attrs(tcx.hir().local_def_id_to_hir_id(def_id))
             .iter()
-            .filter(move |attr| should_encode_attr(tcx, attr, def_id, &mut is_public));
+            .filter(|attr| analyze_attr(attr, &mut state));
+
+        record_array!(self.tables.attributes[def_id.to_def_id()] <- attr_iter);
 
-        record_array!(self.tables.attributes[def_id.to_def_id()] <- attrs.clone());
         let mut attr_flags = AttrFlags::empty();
-        if attrs.any(|attr| attr.may_have_doc_links()) {
+        if state.may_have_doc_links {
             attr_flags |= AttrFlags::MAY_HAVE_DOC_LINKS;
         }
-        if hir_attrs
-            .iter()
-            .filter(|attr| attr.has_name(sym::doc))
-            .filter_map(|attr| attr.meta_item_list())
-            .any(|items| items.iter().any(|item| item.has_name(sym::hidden)))
-        {
+        if state.is_doc_hidden {
             attr_flags |= AttrFlags::IS_DOC_HIDDEN;
         }
         if !attr_flags.is_empty() {
@@ -1189,8 +1207,7 @@ fn encode_def_ids(&mut self) {
                 record!(self.tables.super_predicates_of[def_id] <- self.tcx.super_predicates_of(def_id));
             }
             if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind {
-                let params_in_repr = self.tcx.params_in_repr(def_id);
-                record!(self.tables.params_in_repr[def_id] <- params_in_repr);
+                self.encode_info_for_adt(def_id);
             }
             if should_encode_trait_impl_trait_tys(tcx, def_id)
                 && let Ok(table) = self.tcx.collect_return_position_impl_trait_in_trait_tys(def_id)
@@ -1213,46 +1230,53 @@ fn encode_def_ids(&mut self) {
         }
     }
 
-    fn encode_enum_variant_info(&mut self, def: ty::AdtDef<'tcx>, index: VariantIdx) {
+    #[instrument(level = "trace", skip(self))]
+    fn encode_info_for_adt(&mut self, def_id: DefId) {
         let tcx = self.tcx;
-        let variant = &def.variant(index);
-        let def_id = variant.def_id;
-        debug!("EncodeContext::encode_enum_variant_info({:?})", def_id);
-
-        let data = VariantData {
-            discr: variant.discr,
-            ctor: variant.ctor.map(|(kind, def_id)| (kind, def_id.index)),
-            is_non_exhaustive: variant.is_field_list_non_exhaustive(),
-        };
+        let adt_def = tcx.adt_def(def_id);
+        record!(self.tables.repr_options[def_id] <- adt_def.repr());
 
-        record!(self.tables.variant_data[def_id] <- data);
-        self.tables.constness.set(def_id.index, hir::Constness::Const);
-        record_array!(self.tables.children[def_id] <- variant.fields.iter().map(|f| {
-            assert!(f.did.is_local());
-            f.did.index
-        }));
-        if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor {
-            // FIXME(eddyb) encode signature only in `encode_enum_variant_ctor`.
-            record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(ctor_def_id));
+        let params_in_repr = self.tcx.params_in_repr(def_id);
+        record!(self.tables.params_in_repr[def_id] <- params_in_repr);
+
+        if adt_def.is_enum() {
+            record_array!(self.tables.children[def_id] <- iter::from_generator(||
+                for variant in tcx.adt_def(def_id).variants() {
+                    yield variant.def_id.index;
+                    // Encode constructors which take a separate slot in value namespace.
+                    if let Some(ctor_def_id) = variant.ctor_def_id() {
+                        yield ctor_def_id.index;
+                    }
+                }
+            ));
+        } else {
+            // For non-enum, there is only one variant, and its def_id is the adt's.
+            debug_assert_eq!(adt_def.variants().len(), 1);
+            debug_assert_eq!(adt_def.non_enum_variant().def_id, def_id);
+            // Therefore, the loop over variants will encode its fields as the adt's children.
         }
-    }
 
-    fn encode_enum_variant_ctor(&mut self, def: ty::AdtDef<'tcx>, index: VariantIdx) {
-        let variant = &def.variant(index);
-        let Some((ctor_kind, def_id)) = variant.ctor else { return };
-        debug!("EncodeContext::encode_enum_variant_ctor({:?})", def_id);
+        for variant in adt_def.variants().iter() {
+            let data = VariantData {
+                discr: variant.discr,
+                ctor: variant.ctor.map(|(kind, def_id)| (kind, def_id.index)),
+                is_non_exhaustive: variant.is_field_list_non_exhaustive(),
+            };
+            record!(self.tables.variant_data[variant.def_id] <- data);
 
-        // FIXME(eddyb) encode only the `CtorKind` for constructors.
-        let data = VariantData {
-            discr: variant.discr,
-            ctor: Some((ctor_kind, def_id.index)),
-            is_non_exhaustive: variant.is_field_list_non_exhaustive(),
-        };
+            self.tables.constness.set(variant.def_id.index, hir::Constness::Const);
+            record_array!(self.tables.children[variant.def_id] <- variant.fields.iter().map(|f| {
+                assert!(f.did.is_local());
+                f.did.index
+            }));
 
-        record!(self.tables.variant_data[def_id] <- data);
-        self.tables.constness.set(def_id.index, hir::Constness::Const);
-        if ctor_kind == CtorKind::Fn {
-            record!(self.tables.fn_sig[def_id] <- self.tcx.fn_sig(def_id));
+            if let Some((CtorKind::Fn, ctor_def_id)) = variant.ctor {
+                self.tables.constness.set(ctor_def_id.index, hir::Constness::Const);
+                let fn_sig = tcx.fn_sig(ctor_def_id);
+                record!(self.tables.fn_sig[ctor_def_id] <- fn_sig);
+                // FIXME only encode signature for ctor_def_id
+                record!(self.tables.fn_sig[variant.def_id] <- fn_sig);
+            }
         }
     }
 
@@ -1305,25 +1329,6 @@ fn encode_info_for_mod(&mut self, local_def_id: LocalDefId, md: &hir::Mod<'_>) {
         }
     }
 
-    fn encode_struct_ctor(&mut self, adt_def: ty::AdtDef<'tcx>) {
-        let variant = adt_def.non_enum_variant();
-        let Some((ctor_kind, def_id)) = variant.ctor else { return };
-        debug!("EncodeContext::encode_struct_ctor({:?})", def_id);
-
-        let data = VariantData {
-            discr: variant.discr,
-            ctor: Some((ctor_kind, def_id.index)),
-            is_non_exhaustive: variant.is_field_list_non_exhaustive(),
-        };
-
-        record!(self.tables.repr_options[def_id] <- adt_def.repr());
-        record!(self.tables.variant_data[def_id] <- data);
-        self.tables.constness.set(def_id.index, hir::Constness::Const);
-        if ctor_kind == CtorKind::Fn {
-            record!(self.tables.fn_sig[def_id] <- self.tcx.fn_sig(def_id));
-        }
-    }
-
     fn encode_explicit_item_bounds(&mut self, def_id: DefId) {
         debug!("EncodeContext::encode_explicit_item_bounds({:?})", def_id);
         let bounds = self.tcx.explicit_item_bounds(def_id);
@@ -1532,33 +1537,6 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
                     self.tables.is_type_alias_impl_trait.set_nullable(def_id.index, true);
                 }
             }
-            hir::ItemKind::Enum(..) => {
-                let adt_def = self.tcx.adt_def(def_id);
-                record!(self.tables.repr_options[def_id] <- adt_def.repr());
-            }
-            hir::ItemKind::Struct(..) => {
-                let adt_def = self.tcx.adt_def(def_id);
-                record!(self.tables.repr_options[def_id] <- adt_def.repr());
-                self.tables.constness.set(def_id.index, hir::Constness::Const);
-
-                let variant = adt_def.non_enum_variant();
-                record!(self.tables.variant_data[def_id] <- VariantData {
-                    discr: variant.discr,
-                    ctor: variant.ctor.map(|(kind, def_id)| (kind, def_id.index)),
-                    is_non_exhaustive: variant.is_field_list_non_exhaustive(),
-                });
-            }
-            hir::ItemKind::Union(..) => {
-                let adt_def = self.tcx.adt_def(def_id);
-                record!(self.tables.repr_options[def_id] <- adt_def.repr());
-
-                let variant = adt_def.non_enum_variant();
-                record!(self.tables.variant_data[def_id] <- VariantData {
-                    discr: variant.discr,
-                    ctor: variant.ctor.map(|(kind, def_id)| (kind, def_id.index)),
-                    is_non_exhaustive: variant.is_field_list_non_exhaustive(),
-                });
-            }
             hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
                 self.tables.impl_defaultness.set(def_id.index, *defaultness);
                 self.tables.constness.set(def_id.index, *constness);
@@ -1597,31 +1575,15 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
             }
             hir::ItemKind::Static(..)
             | hir::ItemKind::Const(..)
+            | hir::ItemKind::Enum(..)
+            | hir::ItemKind::Struct(..)
+            | hir::ItemKind::Union(..)
             | hir::ItemKind::ForeignMod { .. }
             | hir::ItemKind::GlobalAsm(..)
             | hir::ItemKind::TyAlias(..) => {}
         };
         // FIXME(eddyb) there should be a nicer way to do this.
         match item.kind {
-            hir::ItemKind::Enum(..) => {
-                record_array!(self.tables.children[def_id] <- iter::from_generator(||
-                    for variant in tcx.adt_def(def_id).variants() {
-                        yield variant.def_id.index;
-                        // Encode constructors which take a separate slot in value namespace.
-                        if let Some(ctor_def_id) = variant.ctor_def_id() {
-                            yield ctor_def_id.index;
-                        }
-                    }
-                ))
-            }
-            hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
-                record_array!(self.tables.children[def_id] <-
-                    self.tcx.adt_def(def_id).non_enum_variant().fields.iter().map(|f| {
-                        assert!(f.did.is_local());
-                        f.did.index
-                    })
-                )
-            }
             hir::ItemKind::Impl { .. } | hir::ItemKind::Trait(..) => {
                 let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id);
                 record_array!(self.tables.children[def_id] <-
@@ -1649,17 +1611,6 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
         // so it's easier to do that here then to wait until we would encounter
         // normally in the visitor walk.
         match item.kind {
-            hir::ItemKind::Enum(..) => {
-                let def = self.tcx.adt_def(item.owner_id.to_def_id());
-                for (i, _) in def.variants().iter_enumerated() {
-                    self.encode_enum_variant_info(def, i);
-                    self.encode_enum_variant_ctor(def, i);
-                }
-            }
-            hir::ItemKind::Struct(..) => {
-                let def = self.tcx.adt_def(item.owner_id.to_def_id());
-                self.encode_struct_ctor(def);
-            }
             hir::ItemKind::Impl { .. } => {
                 for &trait_item_def_id in
                     self.tcx.associated_item_def_ids(item.owner_id.to_def_id()).iter()
index 7e4063c2ffd78fb0f0f2280dbcfade275fce56ad..95148de251824ad0aceb5dbe48777fcbceaeddbc 100644 (file)
@@ -43,6 +43,7 @@
 #![feature(min_specialization)]
 #![feature(trusted_len)]
 #![feature(type_alias_impl_trait)]
+#![feature(strict_provenance)]
 #![feature(associated_type_bounds)]
 #![feature(rustc_attrs)]
 #![feature(control_flow_enum)]
index 5f425a287687e60a562e446be171d156c959ebae..b0975616b6151546773253fb88af57da891f678f 100644 (file)
@@ -110,7 +110,7 @@ macro_rules! throw_machine_stop {
 use rustc_macros::HashStable;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_serialize::{Decodable, Encodable};
-use rustc_target::abi::Endian;
+use rustc_target::abi::{AddressSpace, Endian, HasDataLayout};
 
 use crate::mir;
 use crate::ty::codec::{TyDecoder, TyEncoder};
@@ -438,6 +438,17 @@ pub fn unwrap_vtable(&self) -> (Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tc
             _ => bug!("expected vtable, got {:?}", self),
         }
     }
+
+    /// The address space that this `GlobalAlloc` should be placed in.
+    #[inline]
+    pub fn address_space(&self, cx: &impl HasDataLayout) -> AddressSpace {
+        match self {
+            GlobalAlloc::Function(..) => cx.data_layout().instruction_address_space,
+            GlobalAlloc::Static(..) | GlobalAlloc::Memory(..) | GlobalAlloc::VTable(..) => {
+                AddressSpace::DATA
+            }
+        }
+    }
 }
 
 pub(crate) struct AllocMap<'tcx> {
index 7db86c8d0d4545f355f1b94f7734c713883dbbc9..2e5261331e8be1e782a58d88d78ef2a593a97279 100644 (file)
     ///
     /// This query returns an `&Arc` because codegen backends need the value even after the `TyCtxt`
     /// has been destroyed.
-    query output_filenames(_: ()) -> &'tcx Arc<OutputFilenames> {
+    query output_filenames(_: ()) -> Arc<OutputFilenames> {
         feedable
         desc { "getting output filenames" }
+        arena_cache
     }
 
     /// Do not call this query directly: invoke `normalize` instead.
         separate_provide_extern
     }
 
-    query permits_uninit_init(key: TyAndLayout<'tcx>) -> bool {
-        desc { "checking to see if `{}` permits being left uninit", key.ty }
+    query permits_uninit_init(key: ty::ParamEnvAnd<'tcx, TyAndLayout<'tcx>>) -> bool {
+        desc { "checking to see if `{}` permits being left uninit", key.value.ty }
     }
 
-    query permits_zero_init(key: TyAndLayout<'tcx>) -> bool {
-        desc { "checking to see if `{}` permits being left zeroed", key.ty }
+    query permits_zero_init(key: ty::ParamEnvAnd<'tcx, TyAndLayout<'tcx>>) -> bool {
+        desc { "checking to see if `{}` permits being left zeroed", key.value.ty }
     }
 
     query compare_impl_const(
index bb7fba3ee7119ad9c00af8c9f4311bfd4d5c11b2..47091ca1d69a719ce275a439356088f890294d10 100644 (file)
@@ -130,7 +130,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 /// done only on items with the same name.
 #[derive(Debug, Clone, PartialEq, HashStable)]
 pub struct AssocItems<'tcx> {
-    pub(super) items: SortedIndexMultiMap<u32, Symbol, &'tcx ty::AssocItem>,
+    items: SortedIndexMultiMap<u32, Symbol, &'tcx ty::AssocItem>,
 }
 
 impl<'tcx> AssocItems<'tcx> {
index 0b16270ea987445e6e762ef5fcc817ec64b9ff21..a60c55e8af4d2305571698677e720600568596a1 100644 (file)
@@ -2,6 +2,8 @@
 
 #![allow(rustc::usage_of_ty_tykind)]
 
+pub mod tls;
+
 use crate::arena::Arena;
 use crate::dep_graph::{DepGraph, DepKindStruct};
 use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
@@ -1212,178 +1214,6 @@ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
     Constness, traits::WellFormedLoc, ImplPolarity, crate::mir::ReturnConstraint,
 } }
 
-pub mod tls {
-    use super::{ptr_eq, GlobalCtxt, TyCtxt};
-
-    use crate::dep_graph::TaskDepsRef;
-    use crate::ty::query;
-    use rustc_data_structures::sync::{self, Lock};
-    use rustc_errors::Diagnostic;
-    use std::mem;
-    use thin_vec::ThinVec;
-
-    #[cfg(not(parallel_compiler))]
-    use std::cell::Cell;
-
-    #[cfg(parallel_compiler)]
-    use rustc_rayon_core as rayon_core;
-
-    /// This is the implicit state of rustc. It contains the current
-    /// `TyCtxt` and query. It is updated when creating a local interner or
-    /// executing a new query. Whenever there's a `TyCtxt` value available
-    /// you should also have access to an `ImplicitCtxt` through the functions
-    /// in this module.
-    #[derive(Clone)]
-    pub struct ImplicitCtxt<'a, 'tcx> {
-        /// The current `TyCtxt`.
-        pub tcx: TyCtxt<'tcx>,
-
-        /// The current query job, if any. This is updated by `JobOwner::start` in
-        /// `ty::query::plumbing` when executing a query.
-        pub query: Option<query::QueryJobId>,
-
-        /// Where to store diagnostics for the current query job, if any.
-        /// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query.
-        pub diagnostics: Option<&'a Lock<ThinVec<Diagnostic>>>,
-
-        /// Used to prevent queries from calling too deeply.
-        pub query_depth: usize,
-
-        /// The current dep graph task. This is used to add dependencies to queries
-        /// when executing them.
-        pub task_deps: TaskDepsRef<'a>,
-    }
-
-    impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> {
-        pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self {
-            let tcx = TyCtxt { gcx };
-            ImplicitCtxt {
-                tcx,
-                query: None,
-                diagnostics: None,
-                query_depth: 0,
-                task_deps: TaskDepsRef::Ignore,
-            }
-        }
-    }
-
-    /// Sets Rayon's thread-local variable, which is preserved for Rayon jobs
-    /// to `value` during the call to `f`. It is restored to its previous value after.
-    /// This is used to set the pointer to the new `ImplicitCtxt`.
-    #[cfg(parallel_compiler)]
-    #[inline]
-    fn set_tlv<F: FnOnce() -> R, R>(value: usize, f: F) -> R {
-        rayon_core::tlv::with(value, f)
-    }
-
-    /// Gets Rayon's thread-local variable, which is preserved for Rayon jobs.
-    /// This is used to get the pointer to the current `ImplicitCtxt`.
-    #[cfg(parallel_compiler)]
-    #[inline]
-    pub fn get_tlv() -> usize {
-        rayon_core::tlv::get()
-    }
-
-    #[cfg(not(parallel_compiler))]
-    thread_local! {
-        /// A thread local variable that stores a pointer to the current `ImplicitCtxt`.
-        static TLV: Cell<usize> = const { Cell::new(0) };
-    }
-
-    /// Sets TLV to `value` during the call to `f`.
-    /// It is restored to its previous value after.
-    /// This is used to set the pointer to the new `ImplicitCtxt`.
-    #[cfg(not(parallel_compiler))]
-    #[inline]
-    fn set_tlv<F: FnOnce() -> R, R>(value: usize, f: F) -> R {
-        let old = get_tlv();
-        let _reset = rustc_data_structures::OnDrop(move || TLV.with(|tlv| tlv.set(old)));
-        TLV.with(|tlv| tlv.set(value));
-        f()
-    }
-
-    /// Gets the pointer to the current `ImplicitCtxt`.
-    #[cfg(not(parallel_compiler))]
-    #[inline]
-    fn get_tlv() -> usize {
-        TLV.with(|tlv| tlv.get())
-    }
-
-    /// Sets `context` as the new current `ImplicitCtxt` for the duration of the function `f`.
-    #[inline]
-    pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R
-    where
-        F: FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R,
-    {
-        set_tlv(context as *const _ as usize, || f(&context))
-    }
-
-    /// Allows access to the current `ImplicitCtxt` in a closure if one is available.
-    #[inline]
-    pub fn with_context_opt<F, R>(f: F) -> R
-    where
-        F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R,
-    {
-        let context = get_tlv();
-        if context == 0 {
-            f(None)
-        } else {
-            // We could get an `ImplicitCtxt` pointer from another thread.
-            // Ensure that `ImplicitCtxt` is `Sync`.
-            sync::assert_sync::<ImplicitCtxt<'_, '_>>();
-
-            unsafe { f(Some(&*(context as *const ImplicitCtxt<'_, '_>))) }
-        }
-    }
-
-    /// Allows access to the current `ImplicitCtxt`.
-    /// Panics if there is no `ImplicitCtxt` available.
-    #[inline]
-    pub fn with_context<F, R>(f: F) -> R
-    where
-        F: for<'a, 'tcx> FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R,
-    {
-        with_context_opt(|opt_context| f(opt_context.expect("no ImplicitCtxt stored in tls")))
-    }
-
-    /// Allows access to the current `ImplicitCtxt` whose tcx field is the same as the tcx argument
-    /// passed in. This means the closure is given an `ImplicitCtxt` with the same `'tcx` lifetime
-    /// as the `TyCtxt` passed in.
-    /// This will panic if you pass it a `TyCtxt` which is different from the current
-    /// `ImplicitCtxt`'s `tcx` field.
-    #[inline]
-    pub fn with_related_context<'tcx, F, R>(tcx: TyCtxt<'tcx>, f: F) -> R
-    where
-        F: FnOnce(&ImplicitCtxt<'_, 'tcx>) -> R,
-    {
-        with_context(|context| unsafe {
-            assert!(ptr_eq(context.tcx.gcx, tcx.gcx));
-            let context: &ImplicitCtxt<'_, '_> = mem::transmute(context);
-            f(context)
-        })
-    }
-
-    /// Allows access to the `TyCtxt` in the current `ImplicitCtxt`.
-    /// Panics if there is no `ImplicitCtxt` available.
-    #[inline]
-    pub fn with<F, R>(f: F) -> R
-    where
-        F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R,
-    {
-        with_context(|context| f(context.tcx))
-    }
-
-    /// Allows access to the `TyCtxt` in the current `ImplicitCtxt`.
-    /// The closure is passed None if there is no `ImplicitCtxt` available.
-    #[inline]
-    pub fn with_opt<F, R>(f: F) -> R
-    where
-        F: for<'tcx> FnOnce(Option<TyCtxt<'tcx>>) -> R,
-    {
-        with_context_opt(|opt_context| f(opt_context.map(|context| context.tcx)))
-    }
-}
-
 macro_rules! sty_debug_print {
     ($fmt: expr, $ctxt: expr, $($variant: ident),*) => {{
         // Curious inner module to allow variant names to be used as
@@ -2416,12 +2246,6 @@ pub struct DeducedParamAttrs {
     pub read_only: bool,
 }
 
-// We are comparing types with different invariant lifetimes, so `ptr::eq`
-// won't work for us.
-fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool {
-    t as *const () == u as *const ()
-}
-
 pub fn provide(providers: &mut ty::query::Providers) {
     providers.module_reexports =
         |tcx, id| tcx.resolutions(()).reexport_map.get(&id).map(|v| &v[..]);
diff --git a/compiler/rustc_middle/src/ty/context/tls.rs b/compiler/rustc_middle/src/ty/context/tls.rs
new file mode 100644 (file)
index 0000000..71b025d
--- /dev/null
@@ -0,0 +1,187 @@
+use super::{GlobalCtxt, TyCtxt};
+
+use crate::dep_graph::TaskDepsRef;
+use crate::ty::query;
+use rustc_data_structures::sync::{self, Lock};
+use rustc_errors::Diagnostic;
+use std::mem;
+use std::ptr;
+use thin_vec::ThinVec;
+
+/// This is the implicit state of rustc. It contains the current
+/// `TyCtxt` and query. It is updated when creating a local interner or
+/// executing a new query. Whenever there's a `TyCtxt` value available
+/// you should also have access to an `ImplicitCtxt` through the functions
+/// in this module.
+#[derive(Clone)]
+pub struct ImplicitCtxt<'a, 'tcx> {
+    /// The current `TyCtxt`.
+    pub tcx: TyCtxt<'tcx>,
+
+    /// The current query job, if any. This is updated by `JobOwner::start` in
+    /// `ty::query::plumbing` when executing a query.
+    pub query: Option<query::QueryJobId>,
+
+    /// Where to store diagnostics for the current query job, if any.
+    /// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query.
+    pub diagnostics: Option<&'a Lock<ThinVec<Diagnostic>>>,
+
+    /// Used to prevent queries from calling too deeply.
+    pub query_depth: usize,
+
+    /// The current dep graph task. This is used to add dependencies to queries
+    /// when executing them.
+    pub task_deps: TaskDepsRef<'a>,
+}
+
+impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> {
+    pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self {
+        let tcx = TyCtxt { gcx };
+        ImplicitCtxt {
+            tcx,
+            query: None,
+            diagnostics: None,
+            query_depth: 0,
+            task_deps: TaskDepsRef::Ignore,
+        }
+    }
+}
+
+#[cfg(parallel_compiler)]
+mod tlv {
+    use rustc_rayon_core as rayon_core;
+    use std::ptr;
+
+    /// Gets Rayon's thread-local variable, which is preserved for Rayon jobs.
+    /// This is used to get the pointer to the current `ImplicitCtxt`.
+    #[inline]
+    pub(super) fn get_tlv() -> *const () {
+        ptr::from_exposed_addr(rayon_core::tlv::get())
+    }
+
+    /// Sets Rayon's thread-local variable, which is preserved for Rayon jobs
+    /// to `value` during the call to `f`. It is restored to its previous value after.
+    /// This is used to set the pointer to the new `ImplicitCtxt`.
+    #[inline]
+    pub(super) fn with_tlv<F: FnOnce() -> R, R>(value: *const (), f: F) -> R {
+        rayon_core::tlv::with(value.expose_addr(), f)
+    }
+}
+
+#[cfg(not(parallel_compiler))]
+mod tlv {
+    use std::cell::Cell;
+    use std::ptr;
+
+    thread_local! {
+        /// A thread local variable that stores a pointer to the current `ImplicitCtxt`.
+        static TLV: Cell<*const ()> = const { Cell::new(ptr::null()) };
+    }
+
+    /// Gets the pointer to the current `ImplicitCtxt`.
+    #[inline]
+    pub(super) fn get_tlv() -> *const () {
+        TLV.with(|tlv| tlv.get())
+    }
+
+    /// Sets TLV to `value` during the call to `f`.
+    /// It is restored to its previous value after.
+    /// This is used to set the pointer to the new `ImplicitCtxt`.
+    #[inline]
+    pub(super) fn with_tlv<F: FnOnce() -> R, R>(value: *const (), f: F) -> R {
+        let old = get_tlv();
+        let _reset = rustc_data_structures::OnDrop(move || TLV.with(|tlv| tlv.set(old)));
+        TLV.with(|tlv| tlv.set(value));
+        f()
+    }
+}
+
+#[inline]
+fn erase(context: &ImplicitCtxt<'_, '_>) -> *const () {
+    context as *const _ as *const ()
+}
+
+#[inline]
+unsafe fn downcast<'a, 'tcx>(context: *const ()) -> &'a ImplicitCtxt<'a, 'tcx> {
+    &*(context as *const ImplicitCtxt<'a, 'tcx>)
+}
+
+/// Sets `context` as the new current `ImplicitCtxt` for the duration of the function `f`.
+#[inline]
+pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R
+where
+    F: FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R,
+{
+    tlv::with_tlv(erase(context), || f(&context))
+}
+
+/// Allows access to the current `ImplicitCtxt` in a closure if one is available.
+#[inline]
+pub fn with_context_opt<F, R>(f: F) -> R
+where
+    F: for<'a, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'tcx>>) -> R,
+{
+    let context = tlv::get_tlv();
+    if context.is_null() {
+        f(None)
+    } else {
+        // We could get an `ImplicitCtxt` pointer from another thread.
+        // Ensure that `ImplicitCtxt` is `Sync`.
+        sync::assert_sync::<ImplicitCtxt<'_, '_>>();
+
+        unsafe { f(Some(downcast(context))) }
+    }
+}
+
+/// Allows access to the current `ImplicitCtxt`.
+/// Panics if there is no `ImplicitCtxt` available.
+#[inline]
+pub fn with_context<F, R>(f: F) -> R
+where
+    F: for<'a, 'tcx> FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R,
+{
+    with_context_opt(|opt_context| f(opt_context.expect("no ImplicitCtxt stored in tls")))
+}
+
+/// Allows access to the current `ImplicitCtxt` whose tcx field is the same as the tcx argument
+/// passed in. This means the closure is given an `ImplicitCtxt` with the same `'tcx` lifetime
+/// as the `TyCtxt` passed in.
+/// This will panic if you pass it a `TyCtxt` which is different from the current
+/// `ImplicitCtxt`'s `tcx` field.
+#[inline]
+pub fn with_related_context<'tcx, F, R>(tcx: TyCtxt<'tcx>, f: F) -> R
+where
+    F: FnOnce(&ImplicitCtxt<'_, 'tcx>) -> R,
+{
+    with_context(|context| {
+        // The two gcx have different invariant lifetimes, so we need to erase them for the comparison.
+        assert!(ptr::eq(
+            context.tcx.gcx as *const _ as *const (),
+            tcx.gcx as *const _ as *const ()
+        ));
+
+        let context: &ImplicitCtxt<'_, '_> = unsafe { mem::transmute(context) };
+
+        f(context)
+    })
+}
+
+/// Allows access to the `TyCtxt` in the current `ImplicitCtxt`.
+/// Panics if there is no `ImplicitCtxt` available.
+#[inline]
+pub fn with<F, R>(f: F) -> R
+where
+    F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> R,
+{
+    with_context(|context| f(context.tcx))
+}
+
+/// Allows access to the `TyCtxt` in the current `ImplicitCtxt`.
+/// The closure is passed None if there is no `ImplicitCtxt` available.
+#[inline]
+pub fn with_opt<F, R>(f: F) -> R
+where
+    F: for<'tcx> FnOnce(Option<TyCtxt<'tcx>>) -> R,
+{
+    with_context_opt(|opt_context| f(opt_context.map(|context| context.tcx)))
+}
index 5d394f71f0d764024b33c0f2e4f047a61a8743e9..c8a700c4e280d6eccd2d19ba8face8a430a6d31f 100644 (file)
@@ -1,24 +1,18 @@
-use crate::traits::{ObligationCause, ObligationCauseCode};
-use crate::ty::diagnostics::suggest_constraining_type_param;
-use crate::ty::print::{with_forced_trimmed_paths, FmtPrinter, Printer};
+use crate::ty::print::{with_forced_trimmed_paths, FmtPrinter, PrettyPrinter};
 use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
-use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
-use rustc_errors::{pluralize, Diagnostic, MultiSpan};
+use rustc_errors::pluralize;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind};
 use rustc_hir::def_id::DefId;
-use rustc_span::symbol::{sym, Symbol};
-use rustc_span::{BytePos, Span};
+use rustc_span::symbol::Symbol;
 use rustc_target::spec::abi;
-
 use std::borrow::Cow;
 use std::collections::hash_map::DefaultHasher;
 use std::fmt;
-use std::hash::{Hash, Hasher};
+use std::hash::Hash;
+use std::hash::Hasher;
 use std::path::PathBuf;
 
-use super::print::PrettyPrinter;
-
 #[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable, TypeVisitable, Lift)]
 pub struct ExpectedFound<T> {
     pub expected: T,
@@ -391,620 +385,6 @@ pub fn prefix_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
 }
 
 impl<'tcx> TyCtxt<'tcx> {
-    pub fn note_and_explain_type_err(
-        self,
-        diag: &mut Diagnostic,
-        err: TypeError<'tcx>,
-        cause: &ObligationCause<'tcx>,
-        sp: Span,
-        body_owner_def_id: DefId,
-    ) {
-        use self::TypeError::*;
-        debug!("note_and_explain_type_err err={:?} cause={:?}", err, cause);
-        match err {
-            ArgumentSorts(values, _) | Sorts(values) => {
-                match (values.expected.kind(), values.found.kind()) {
-                    (ty::Closure(..), ty::Closure(..)) => {
-                        diag.note("no two closures, even if identical, have the same type");
-                        diag.help("consider boxing your closure and/or using it as a trait object");
-                    }
-                    (ty::Alias(ty::Opaque, ..), ty::Alias(ty::Opaque, ..)) => {
-                        // Issue #63167
-                        diag.note("distinct uses of `impl Trait` result in different opaque types");
-                    }
-                    (ty::Float(_), ty::Infer(ty::IntVar(_)))
-                        if let Ok(
-                            // Issue #53280
-                            snippet,
-                        ) = self.sess.source_map().span_to_snippet(sp) =>
-                    {
-                        if snippet.chars().all(|c| c.is_digit(10) || c == '-' || c == '_') {
-                            diag.span_suggestion(
-                                sp,
-                                "use a float literal",
-                                format!("{}.0", snippet),
-                                MachineApplicable,
-                            );
-                        }
-                    }
-                    (ty::Param(expected), ty::Param(found)) => {
-                        let generics = self.generics_of(body_owner_def_id);
-                        let e_span = self.def_span(generics.type_param(expected, self).def_id);
-                        if !sp.contains(e_span) {
-                            diag.span_label(e_span, "expected type parameter");
-                        }
-                        let f_span = self.def_span(generics.type_param(found, self).def_id);
-                        if !sp.contains(f_span) {
-                            diag.span_label(f_span, "found type parameter");
-                        }
-                        diag.note(
-                            "a type parameter was expected, but a different one was found; \
-                             you might be missing a type parameter or trait bound",
-                        );
-                        diag.note(
-                            "for more information, visit \
-                             https://doc.rust-lang.org/book/ch10-02-traits.html\
-                             #traits-as-parameters",
-                        );
-                    }
-                    (ty::Alias(ty::Projection, _), ty::Alias(ty::Projection, _)) => {
-                        diag.note("an associated type was expected, but a different one was found");
-                    }
-                    (ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
-                        if self.def_kind(proj.def_id) != DefKind::ImplTraitPlaceholder =>
-                    {
-                        let generics = self.generics_of(body_owner_def_id);
-                        let p_span = self.def_span(generics.type_param(p, self).def_id);
-                        if !sp.contains(p_span) {
-                            diag.span_label(p_span, "this type parameter");
-                        }
-                        let hir = self.hir();
-                        let mut note = true;
-                        if let Some(generics) = generics
-                            .type_param(p, self)
-                            .def_id
-                            .as_local()
-                            .map(|id| hir.local_def_id_to_hir_id(id))
-                            .and_then(|id| self.hir().find_parent(id))
-                            .as_ref()
-                            .and_then(|node| node.generics())
-                        {
-                            // Synthesize the associated type restriction `Add<Output = Expected>`.
-                            // FIXME: extract this logic for use in other diagnostics.
-                            let (trait_ref, assoc_substs) = proj.trait_ref_and_own_substs(self);
-                            let path =
-                                self.def_path_str_with_substs(trait_ref.def_id, trait_ref.substs);
-                            let item_name = self.item_name(proj.def_id);
-                            let item_args = self.format_generic_args(assoc_substs);
-
-                            let path = if path.ends_with('>') {
-                                format!(
-                                    "{}, {}{} = {}>",
-                                    &path[..path.len() - 1],
-                                    item_name,
-                                    item_args,
-                                    p
-                                )
-                            } else {
-                                format!("{}<{}{} = {}>", path, item_name, item_args, p)
-                            };
-                            note = !suggest_constraining_type_param(
-                                self,
-                                generics,
-                                diag,
-                                &format!("{}", proj.self_ty()),
-                                &path,
-                                None,
-                            );
-                        }
-                        if note {
-                            diag.note("you might be missing a type parameter or trait bound");
-                        }
-                    }
-                    (ty::Param(p), ty::Dynamic(..) | ty::Alias(ty::Opaque, ..))
-                    | (ty::Dynamic(..) | ty::Alias(ty::Opaque, ..), ty::Param(p)) => {
-                        let generics = self.generics_of(body_owner_def_id);
-                        let p_span = self.def_span(generics.type_param(p, self).def_id);
-                        if !sp.contains(p_span) {
-                            diag.span_label(p_span, "this type parameter");
-                        }
-                        diag.help("type parameters must be constrained to match other types");
-                        if self.sess.teach(&diag.get_code().unwrap()) {
-                            diag.help(
-                                "given a type parameter `T` and a method `foo`:
-```
-trait Trait<T> { fn foo(&self) -> T; }
-```
-the only ways to implement method `foo` are:
-- constrain `T` with an explicit type:
-```
-impl Trait<String> for X {
-    fn foo(&self) -> String { String::new() }
-}
-```
-- add a trait bound to `T` and call a method on that trait that returns `Self`:
-```
-impl<T: std::default::Default> Trait<T> for X {
-    fn foo(&self) -> T { <T as std::default::Default>::default() }
-}
-```
-- change `foo` to return an argument of type `T`:
-```
-impl<T> Trait<T> for X {
-    fn foo(&self, x: T) -> T { x }
-}
-```",
-                            );
-                        }
-                        diag.note(
-                            "for more information, visit \
-                             https://doc.rust-lang.org/book/ch10-02-traits.html\
-                             #traits-as-parameters",
-                        );
-                    }
-                    (ty::Param(p), ty::Closure(..) | ty::Generator(..)) => {
-                        let generics = self.generics_of(body_owner_def_id);
-                        let p_span = self.def_span(generics.type_param(p, self).def_id);
-                        if !sp.contains(p_span) {
-                            diag.span_label(p_span, "this type parameter");
-                        }
-                        diag.help(&format!(
-                            "every closure has a distinct type and so could not always match the \
-                             caller-chosen type of parameter `{}`",
-                            p
-                        ));
-                    }
-                    (ty::Param(p), _) | (_, ty::Param(p)) => {
-                        let generics = self.generics_of(body_owner_def_id);
-                        let p_span = self.def_span(generics.type_param(p, self).def_id);
-                        if !sp.contains(p_span) {
-                            diag.span_label(p_span, "this type parameter");
-                        }
-                    }
-                    (ty::Alias(ty::Projection, proj_ty), _) if self.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => {
-                        self.expected_projection(
-                            diag,
-                            proj_ty,
-                            values,
-                            body_owner_def_id,
-                            cause.code(),
-                        );
-                    }
-                    (_, ty::Alias(ty::Projection, proj_ty)) if self.def_kind(proj_ty.def_id) != DefKind::ImplTraitPlaceholder => {
-                        let msg = format!(
-                            "consider constraining the associated type `{}` to `{}`",
-                            values.found, values.expected,
-                        );
-                        if !(self.suggest_constraining_opaque_associated_type(
-                            diag,
-                            &msg,
-                            proj_ty,
-                            values.expected,
-                        ) || self.suggest_constraint(
-                            diag,
-                            &msg,
-                            body_owner_def_id,
-                            proj_ty,
-                            values.expected,
-                        )) {
-                            diag.help(&msg);
-                            diag.note(
-                                "for more information, visit \
-                                https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
-                            );
-                        }
-                    }
-                    _ => {}
-                }
-                debug!(
-                    "note_and_explain_type_err expected={:?} ({:?}) found={:?} ({:?})",
-                    values.expected,
-                    values.expected.kind(),
-                    values.found,
-                    values.found.kind(),
-                );
-            }
-            CyclicTy(ty) => {
-                // Watch out for various cases of cyclic types and try to explain.
-                if ty.is_closure() || ty.is_generator() {
-                    diag.note(
-                        "closures cannot capture themselves or take themselves as argument;\n\
-                         this error may be the result of a recent compiler bug-fix,\n\
-                         see issue #46062 <https://github.com/rust-lang/rust/issues/46062>\n\
-                         for more information",
-                    );
-                }
-            }
-            TargetFeatureCast(def_id) => {
-                let target_spans =
-                    self.get_attrs(def_id, sym::target_feature).map(|attr| attr.span);
-                diag.note(
-                    "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers"
-                );
-                diag.span_labels(target_spans, "`#[target_feature]` added here");
-            }
-            _ => {}
-        }
-    }
-
-    fn suggest_constraint(
-        self,
-        diag: &mut Diagnostic,
-        msg: &str,
-        body_owner_def_id: DefId,
-        proj_ty: &ty::AliasTy<'tcx>,
-        ty: Ty<'tcx>,
-    ) -> bool {
-        let assoc = self.associated_item(proj_ty.def_id);
-        let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
-        if let Some(item) = self.hir().get_if_local(body_owner_def_id) {
-            if let Some(hir_generics) = item.generics() {
-                // Get the `DefId` for the type parameter corresponding to `A` in `<A as T>::Foo`.
-                // This will also work for `impl Trait`.
-                let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind() {
-                    let generics = self.generics_of(body_owner_def_id);
-                    generics.type_param(param_ty, self).def_id
-                } else {
-                    return false;
-                };
-                let Some(def_id) = def_id.as_local() else {
-                    return false;
-                };
-
-                // First look in the `where` clause, as this might be
-                // `fn foo<T>(x: T) where T: Trait`.
-                for pred in hir_generics.bounds_for_param(def_id) {
-                    if self.constrain_generic_bound_associated_type_structured_suggestion(
-                        diag,
-                        &trait_ref,
-                        pred.bounds,
-                        &assoc,
-                        assoc_substs,
-                        ty,
-                        msg,
-                        false,
-                    ) {
-                        return true;
-                    }
-                }
-            }
-        }
-        false
-    }
-
-    /// An associated type was expected and a different type was found.
-    ///
-    /// We perform a few different checks to see what we can suggest:
-    ///
-    ///  - In the current item, look for associated functions that return the expected type and
-    ///    suggest calling them. (Not a structured suggestion.)
-    ///  - If any of the item's generic bounds can be constrained, we suggest constraining the
-    ///    associated type to the found type.
-    ///  - If the associated type has a default type and was expected inside of a `trait`, we
-    ///    mention that this is disallowed.
-    ///  - If all other things fail, and the error is not because of a mismatch between the `trait`
-    ///    and the `impl`, we provide a generic `help` to constrain the assoc type or call an assoc
-    ///    fn that returns the type.
-    fn expected_projection(
-        self,
-        diag: &mut Diagnostic,
-        proj_ty: &ty::AliasTy<'tcx>,
-        values: ExpectedFound<Ty<'tcx>>,
-        body_owner_def_id: DefId,
-        cause_code: &ObligationCauseCode<'_>,
-    ) {
-        let msg = format!(
-            "consider constraining the associated type `{}` to `{}`",
-            values.expected, values.found
-        );
-        let body_owner = self.hir().get_if_local(body_owner_def_id);
-        let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name);
-
-        // We don't want to suggest calling an assoc fn in a scope where that isn't feasible.
-        let callable_scope = matches!(
-            body_owner,
-            Some(
-                hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })
-                    | hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(..), .. })
-                    | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }),
-            )
-        );
-        let impl_comparison =
-            matches!(cause_code, ObligationCauseCode::CompareImplItemObligation { .. });
-        let assoc = self.associated_item(proj_ty.def_id);
-        if !callable_scope || impl_comparison {
-            // We do not want to suggest calling functions when the reason of the
-            // type error is a comparison of an `impl` with its `trait` or when the
-            // scope is outside of a `Body`.
-        } else {
-            // If we find a suitable associated function that returns the expected type, we don't
-            // want the more general suggestion later in this method about "consider constraining
-            // the associated type or calling a method that returns the associated type".
-            let point_at_assoc_fn = self.point_at_methods_that_satisfy_associated_type(
-                diag,
-                assoc.container_id(self),
-                current_method_ident,
-                proj_ty.def_id,
-                values.expected,
-            );
-            // Possibly suggest constraining the associated type to conform to the
-            // found type.
-            if self.suggest_constraint(diag, &msg, body_owner_def_id, proj_ty, values.found)
-                || point_at_assoc_fn
-            {
-                return;
-            }
-        }
-
-        self.suggest_constraining_opaque_associated_type(diag, &msg, proj_ty, values.found);
-
-        if self.point_at_associated_type(diag, body_owner_def_id, values.found) {
-            return;
-        }
-
-        if !impl_comparison {
-            // Generic suggestion when we can't be more specific.
-            if callable_scope {
-                diag.help(&format!(
-                    "{} or calling a method that returns `{}`",
-                    msg, values.expected
-                ));
-            } else {
-                diag.help(&msg);
-            }
-            diag.note(
-                "for more information, visit \
-                 https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
-            );
-        }
-        if self.sess.teach(&diag.get_code().unwrap()) {
-            diag.help(
-                "given an associated type `T` and a method `foo`:
-```
-trait Trait {
-type T;
-fn foo(&self) -> Self::T;
-}
-```
-the only way of implementing method `foo` is to constrain `T` with an explicit associated type:
-```
-impl Trait for X {
-type T = String;
-fn foo(&self) -> Self::T { String::new() }
-}
-```",
-            );
-        }
-    }
-
-    /// When the expected `impl Trait` is not defined in the current item, it will come from
-    /// a return type. This can occur when dealing with `TryStream` (#71035).
-    fn suggest_constraining_opaque_associated_type(
-        self,
-        diag: &mut Diagnostic,
-        msg: &str,
-        proj_ty: &ty::AliasTy<'tcx>,
-        ty: Ty<'tcx>,
-    ) -> bool {
-        let assoc = self.associated_item(proj_ty.def_id);
-        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 {
-                    hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
-                    _ => bug!("The HirId comes from a `ty::Opaque`"),
-                }
-            } else {
-                return false;
-            };
-
-            let (trait_ref, assoc_substs) = proj_ty.trait_ref_and_own_substs(self);
-
-            self.constrain_generic_bound_associated_type_structured_suggestion(
-                diag,
-                &trait_ref,
-                opaque_hir_ty.bounds,
-                assoc,
-                assoc_substs,
-                ty,
-                msg,
-                true,
-            )
-        } else {
-            false
-        }
-    }
-
-    fn point_at_methods_that_satisfy_associated_type(
-        self,
-        diag: &mut Diagnostic,
-        assoc_container_id: DefId,
-        current_method_ident: Option<Symbol>,
-        proj_ty_item_def_id: DefId,
-        expected: Ty<'tcx>,
-    ) -> bool {
-        let items = self.associated_items(assoc_container_id);
-        // Find all the methods in the trait that could be called to construct the
-        // expected associated type.
-        // FIXME: consider suggesting the use of associated `const`s.
-        let methods: Vec<(Span, String)> = items
-            .items
-            .iter()
-            .filter(|(name, item)| {
-                ty::AssocKind::Fn == item.kind && Some(**name) != current_method_ident
-            })
-            .filter_map(|(_, item)| {
-                let method = self.fn_sig(item.def_id);
-                match *method.output().skip_binder().kind() {
-                    ty::Alias(ty::Projection, ty::AliasTy { def_id: item_def_id, .. })
-                        if item_def_id == proj_ty_item_def_id =>
-                    {
-                        Some((
-                            self.def_span(item.def_id),
-                            format!("consider calling `{}`", self.def_path_str(item.def_id)),
-                        ))
-                    }
-                    _ => None,
-                }
-            })
-            .collect();
-        if !methods.is_empty() {
-            // Use a single `help:` to show all the methods in the trait that can
-            // be used to construct the expected associated type.
-            let mut span: MultiSpan =
-                methods.iter().map(|(sp, _)| *sp).collect::<Vec<Span>>().into();
-            let msg = format!(
-                "{some} method{s} {are} available that return{r} `{ty}`",
-                some = if methods.len() == 1 { "a" } else { "some" },
-                s = pluralize!(methods.len()),
-                are = pluralize!("is", methods.len()),
-                r = if methods.len() == 1 { "s" } else { "" },
-                ty = expected
-            );
-            for (sp, label) in methods.into_iter() {
-                span.push_span_label(sp, label);
-            }
-            diag.span_help(span, &msg);
-            return true;
-        }
-        false
-    }
-
-    fn point_at_associated_type(
-        self,
-        diag: &mut Diagnostic,
-        body_owner_def_id: DefId,
-        found: Ty<'tcx>,
-    ) -> bool {
-        let Some(hir_id) = body_owner_def_id.as_local() else {
-            return false;
-        };
-        let hir_id = self.hir().local_def_id_to_hir_id(hir_id);
-        // When `body_owner` is an `impl` or `trait` item, look in its associated types for
-        // `expected` and point at it.
-        let parent_id = self.hir().get_parent_item(hir_id);
-        let item = self.hir().find_by_def_id(parent_id.def_id);
-        debug!("expected_projection parent item {:?}", item);
-        match item {
-            Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. })) => {
-                // FIXME: account for `#![feature(specialization)]`
-                for item in &items[..] {
-                    match item.kind {
-                        hir::AssocItemKind::Type => {
-                            // FIXME: account for returning some type in a trait fn impl that has
-                            // an assoc type as a return type (#72076).
-                            if let hir::Defaultness::Default { has_value: true } =
-                                self.impl_defaultness(item.id.owner_id)
-                            {
-                                if self.type_of(item.id.owner_id) == found {
-                                    diag.span_label(
-                                        item.span,
-                                        "associated type defaults can't be assumed inside the \
-                                            trait defining them",
-                                    );
-                                    return true;
-                                }
-                            }
-                        }
-                        _ => {}
-                    }
-                }
-            }
-            Some(hir::Node::Item(hir::Item {
-                kind: hir::ItemKind::Impl(hir::Impl { items, .. }),
-                ..
-            })) => {
-                for item in &items[..] {
-                    if let hir::AssocItemKind::Type = item.kind {
-                        if self.type_of(item.id.owner_id) == found {
-                            diag.span_label(item.span, "expected this associated type");
-                            return true;
-                        }
-                    }
-                }
-            }
-            _ => {}
-        }
-        false
-    }
-
-    /// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref`
-    /// requirement, provide a structured suggestion to constrain it to a given type `ty`.
-    ///
-    /// `is_bound_surely_present` indicates whether we know the bound we're looking for is
-    /// inside `bounds`. If that's the case then we can consider `bounds` containing only one
-    /// trait bound as the one we're looking for. This can help in cases where the associated
-    /// type is defined on a supertrait of the one present in the bounds.
-    fn constrain_generic_bound_associated_type_structured_suggestion(
-        self,
-        diag: &mut Diagnostic,
-        trait_ref: &ty::TraitRef<'tcx>,
-        bounds: hir::GenericBounds<'_>,
-        assoc: &ty::AssocItem,
-        assoc_substs: &[ty::GenericArg<'tcx>],
-        ty: Ty<'tcx>,
-        msg: &str,
-        is_bound_surely_present: bool,
-    ) -> bool {
-        // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting.
-
-        let trait_bounds = bounds.iter().filter_map(|bound| match bound {
-            hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => Some(ptr),
-            _ => None,
-        });
-
-        let matching_trait_bounds = trait_bounds
-            .clone()
-            .filter(|ptr| ptr.trait_ref.trait_def_id() == Some(trait_ref.def_id))
-            .collect::<Vec<_>>();
-
-        let span = match &matching_trait_bounds[..] {
-            &[ptr] => ptr.span,
-            &[] if is_bound_surely_present => match &trait_bounds.collect::<Vec<_>>()[..] {
-                &[ptr] => ptr.span,
-                _ => return false,
-            },
-            _ => return false,
-        };
-
-        self.constrain_associated_type_structured_suggestion(
-            diag,
-            span,
-            assoc,
-            assoc_substs,
-            ty,
-            msg,
-        )
-    }
-
-    /// Given a span corresponding to a bound, provide a structured suggestion to set an
-    /// associated type to a given type `ty`.
-    fn constrain_associated_type_structured_suggestion(
-        self,
-        diag: &mut Diagnostic,
-        span: Span,
-        assoc: &ty::AssocItem,
-        assoc_substs: &[ty::GenericArg<'tcx>],
-        ty: Ty<'tcx>,
-        msg: &str,
-    ) -> bool {
-        if let Ok(has_params) =
-            self.sess.source_map().span_to_snippet(span).map(|snippet| snippet.ends_with('>'))
-        {
-            let (span, sugg) = if has_params {
-                let pos = span.hi() - BytePos(1);
-                let span = Span::new(pos, pos, span.ctxt(), span.parent());
-                (span, format!(", {} = {}", assoc.ident(self), ty))
-            } else {
-                let item_args = self.format_generic_args(assoc_substs);
-                (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident(self), item_args, ty))
-            };
-            diag.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
-            return true;
-        }
-        false
-    }
-
     pub fn short_ty_string(self, ty: Ty<'tcx>) -> (String, Option<PathBuf>) {
         let width = self.sess.diagnostic_width();
         let length_limit = width.saturating_sub(30);
@@ -1047,11 +427,4 @@ pub fn short_ty_string(self, ty: Ty<'tcx>) -> (String, Option<PathBuf>) {
             Err(_) => (regular, None),
         }
     }
-
-    fn format_generic_args(self, args: &[ty::GenericArg<'tcx>]) -> String {
-        FmtPrinter::new(self, hir::def::Namespace::TypeNS)
-            .path_generic_args(Ok, args)
-            .expect("could not write to `String`.")
-            .into_buffer()
-    }
 }
index dfd016569c27a51de3135d2dbcef1706291d9747..66b9d96e69577606abaec0bd90a1c0be9a723761 100644 (file)
@@ -128,7 +128,8 @@ fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
             Int(i, signed) => i.to_ty(tcx, signed),
             F32 => tcx.types.f32,
             F64 => tcx.types.f64,
-            Pointer => tcx.mk_mut_ptr(tcx.mk_unit()),
+            // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
+            Pointer(_) => tcx.mk_mut_ptr(tcx.mk_unit()),
         }
     }
 
@@ -138,7 +139,11 @@ fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
     fn to_int_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         match *self {
             Int(i, signed) => i.to_ty(tcx, signed),
-            Pointer => tcx.types.usize,
+            // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
+            Pointer(_) => {
+                let signed = false;
+                tcx.data_layout().ptr_sized_integer().to_ty(tcx, signed)
+            }
             F32 | F64 => bug!("floats do not have an int type"),
         }
     }
@@ -812,132 +817,125 @@ fn ty_and_layout_pointee_info_at(
         let tcx = cx.tcx();
         let param_env = cx.param_env();
 
-        let addr_space_of_ty = |ty: Ty<'tcx>| {
-            if ty.is_fn() { cx.data_layout().instruction_address_space } else { AddressSpace::DATA }
-        };
-
-        let pointee_info = match *this.ty.kind() {
-            ty::RawPtr(mt) if offset.bytes() == 0 => {
-                tcx.layout_of(param_env.and(mt.ty)).ok().map(|layout| PointeeInfo {
-                    size: layout.size,
-                    align: layout.align.abi,
-                    safe: None,
-                    address_space: addr_space_of_ty(mt.ty),
-                })
-            }
-            ty::FnPtr(fn_sig) if offset.bytes() == 0 => {
-                tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| PointeeInfo {
-                    size: layout.size,
-                    align: layout.align.abi,
-                    safe: None,
-                    address_space: cx.data_layout().instruction_address_space,
-                })
-            }
-            ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
-                let address_space = addr_space_of_ty(ty);
-                let kind = if tcx.sess.opts.optimize == OptLevel::No {
-                    // Use conservative pointer kind if not optimizing. This saves us the
-                    // Freeze/Unpin queries, and can save time in the codegen backend (noalias
-                    // attributes in LLVM have compile-time cost even in unoptimized builds).
-                    PointerKind::SharedMutable
-                } else {
-                    match mt {
-                        hir::Mutability::Not => {
-                            if ty.is_freeze(tcx, cx.param_env()) {
-                                PointerKind::Frozen
-                            } else {
-                                PointerKind::SharedMutable
+        let pointee_info =
+            match *this.ty.kind() {
+                ty::RawPtr(mt) if offset.bytes() == 0 => {
+                    tcx.layout_of(param_env.and(mt.ty)).ok().map(|layout| PointeeInfo {
+                        size: layout.size,
+                        align: layout.align.abi,
+                        safe: None,
+                    })
+                }
+                ty::FnPtr(fn_sig) if offset.bytes() == 0 => {
+                    tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| {
+                        PointeeInfo { size: layout.size, align: layout.align.abi, safe: None }
+                    })
+                }
+                ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
+                    let kind = if tcx.sess.opts.optimize == OptLevel::No {
+                        // Use conservative pointer kind if not optimizing. This saves us the
+                        // Freeze/Unpin queries, and can save time in the codegen backend (noalias
+                        // attributes in LLVM have compile-time cost even in unoptimized builds).
+                        PointerKind::SharedMutable
+                    } else {
+                        match mt {
+                            hir::Mutability::Not => {
+                                if ty.is_freeze(tcx, cx.param_env()) {
+                                    PointerKind::Frozen
+                                } else {
+                                    PointerKind::SharedMutable
+                                }
                             }
-                        }
-                        hir::Mutability::Mut => {
-                            // References to self-referential structures should not be considered
-                            // noalias, as another pointer to the structure can be obtained, that
-                            // is not based-on the original reference. We consider all !Unpin
-                            // types to be potentially self-referential here.
-                            if ty.is_unpin(tcx, cx.param_env()) {
-                                PointerKind::UniqueBorrowed
-                            } else {
-                                PointerKind::UniqueBorrowedPinned
+                            hir::Mutability::Mut => {
+                                // References to self-referential structures should not be considered
+                                // noalias, as another pointer to the structure can be obtained, that
+                                // is not based-on the original reference. We consider all !Unpin
+                                // types to be potentially self-referential here.
+                                if ty.is_unpin(tcx, cx.param_env()) {
+                                    PointerKind::UniqueBorrowed
+                                } else {
+                                    PointerKind::UniqueBorrowedPinned
+                                }
                             }
                         }
-                    }
-                };
+                    };
 
-                tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo {
-                    size: layout.size,
-                    align: layout.align.abi,
-                    safe: Some(kind),
-                    address_space,
-                })
-            }
+                    tcx.layout_of(param_env.and(ty)).ok().map(|layout| PointeeInfo {
+                        size: layout.size,
+                        align: layout.align.abi,
+                        safe: Some(kind),
+                    })
+                }
 
-            _ => {
-                let mut data_variant = match this.variants {
-                    // Within the discriminant field, only the niche itself is
-                    // always initialized, so we only check for a pointer at its
-                    // offset.
-                    //
-                    // If the niche is a pointer, it's either valid (according
-                    // to its type), or null (which the niche field's scalar
-                    // validity range encodes). This allows using
-                    // `dereferenceable_or_null` for e.g., `Option<&T>`, and
-                    // this will continue to work as long as we don't start
-                    // using more niches than just null (e.g., the first page of
-                    // the address space, or unaligned pointers).
-                    Variants::Multiple {
-                        tag_encoding: TagEncoding::Niche { untagged_variant, .. },
-                        tag_field,
-                        ..
-                    } if this.fields.offset(tag_field) == offset => {
-                        Some(this.for_variant(cx, untagged_variant))
-                    }
-                    _ => Some(this),
-                };
+                _ => {
+                    let mut data_variant = match this.variants {
+                        // Within the discriminant field, only the niche itself is
+                        // always initialized, so we only check for a pointer at its
+                        // offset.
+                        //
+                        // If the niche is a pointer, it's either valid (according
+                        // to its type), or null (which the niche field's scalar
+                        // validity range encodes). This allows using
+                        // `dereferenceable_or_null` for e.g., `Option<&T>`, and
+                        // this will continue to work as long as we don't start
+                        // using more niches than just null (e.g., the first page of
+                        // the address space, or unaligned pointers).
+                        Variants::Multiple {
+                            tag_encoding: TagEncoding::Niche { untagged_variant, .. },
+                            tag_field,
+                            ..
+                        } if this.fields.offset(tag_field) == offset => {
+                            Some(this.for_variant(cx, untagged_variant))
+                        }
+                        _ => Some(this),
+                    };
 
-                if let Some(variant) = data_variant {
-                    // We're not interested in any unions.
-                    if let FieldsShape::Union(_) = variant.fields {
-                        data_variant = None;
+                    if let Some(variant) = data_variant {
+                        // We're not interested in any unions.
+                        if let FieldsShape::Union(_) = variant.fields {
+                            data_variant = None;
+                        }
                     }
-                }
 
-                let mut result = None;
-
-                if let Some(variant) = data_variant {
-                    let ptr_end = offset + Pointer.size(cx);
-                    for i in 0..variant.fields.count() {
-                        let field_start = variant.fields.offset(i);
-                        if field_start <= offset {
-                            let field = variant.field(cx, i);
-                            result = field.to_result().ok().and_then(|field| {
-                                if ptr_end <= field_start + field.size {
-                                    // We found the right field, look inside it.
-                                    let field_info =
-                                        field.pointee_info_at(cx, offset - field_start);
-                                    field_info
-                                } else {
-                                    None
+                    let mut result = None;
+
+                    if let Some(variant) = data_variant {
+                        // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
+                        // (requires passing in the expected address space from the caller)
+                        let ptr_end = offset + Pointer(AddressSpace::DATA).size(cx);
+                        for i in 0..variant.fields.count() {
+                            let field_start = variant.fields.offset(i);
+                            if field_start <= offset {
+                                let field = variant.field(cx, i);
+                                result = field.to_result().ok().and_then(|field| {
+                                    if ptr_end <= field_start + field.size {
+                                        // We found the right field, look inside it.
+                                        let field_info =
+                                            field.pointee_info_at(cx, offset - field_start);
+                                        field_info
+                                    } else {
+                                        None
+                                    }
+                                });
+                                if result.is_some() {
+                                    break;
                                 }
-                            });
-                            if result.is_some() {
-                                break;
                             }
                         }
                     }
-                }
 
-                // FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`.
-                if let Some(ref mut pointee) = result {
-                    if let ty::Adt(def, _) = this.ty.kind() {
-                        if def.is_box() && offset.bytes() == 0 {
-                            pointee.safe = Some(PointerKind::UniqueOwned);
+                    // FIXME(eddyb) This should be for `ptr::Unique<T>`, not `Box<T>`.
+                    if let Some(ref mut pointee) = result {
+                        if let ty::Adt(def, _) = this.ty.kind() {
+                            if def.is_box() && offset.bytes() == 0 {
+                                pointee.safe = Some(PointerKind::UniqueOwned);
+                            }
                         }
                     }
-                }
 
-                result
-            }
-        };
+                    result
+                }
+            };
 
         debug!(
             "pointee_info_at (offset={:?}, type kind: {:?}) => {:?}",
index 9d4ee22a7273beba58c8cb282379a132a7585c03..28b9bdf566018b06c4dab41fdb7b15d601dcb851 100644 (file)
@@ -441,6 +441,10 @@ pub fn def_kind(self, def_id: impl IntoQueryParam<DefId>) -> DefKind {
         self.opt_def_kind(def_id)
             .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id))
     }
+
+    pub fn bound_type_of(self, def_id: impl IntoQueryParam<DefId>) -> ty::EarlyBinder<Ty<'tcx>> {
+        ty::EarlyBinder(self.type_of(def_id))
+    }
 }
 
 impl<'tcx> TyCtxtAt<'tcx> {
@@ -449,4 +453,8 @@ pub fn def_kind(self, def_id: impl IntoQueryParam<DefId>) -> DefKind {
         self.opt_def_kind(def_id)
             .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id))
     }
+
+    pub fn bound_type_of(self, def_id: impl IntoQueryParam<DefId>) -> ty::EarlyBinder<Ty<'tcx>> {
+        ty::EarlyBinder(self.type_of(def_id))
+    }
 }
index 7d4d35b7fdf940fd23ae8924f2db2e9a9b9a376e..2de886a3e817fd3631520137bec368ee74885b78 100644 (file)
@@ -11,6 +11,7 @@
 use rustc_data_structures::functor::IdFunctor;
 use rustc_hir::def::Namespace;
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_target::abi::TyAndLayout;
 
 use std::fmt;
 use std::mem::ManuallyDrop;
@@ -853,3 +854,9 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow
         self.substs.visit_with(visitor)
     }
 }
+
+impl<'tcx> TypeVisitable<'tcx> for TyAndLayout<'tcx, Ty<'tcx>> {
+    fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+        visitor.visit_ty(self.ty)
+    }
+}
index 60076c8cb5f9936d0e16e93798b279fb0d2a0fdc..95abbb50380176be8da44382f48cc725816a1186 100644 (file)
@@ -3,7 +3,6 @@
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::mir;
 use crate::ty::layout::IntegerExt;
-use crate::ty::query::TyCtxtAt;
 use crate::ty::{
     self, DefIdTree, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
     TypeVisitable,
@@ -637,10 +636,6 @@ pub fn try_expand_impl_trait_type(
         if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) }
     }
 
-    pub fn bound_type_of(self, def_id: DefId) -> ty::EarlyBinder<Ty<'tcx>> {
-        ty::EarlyBinder(self.type_of(def_id))
-    }
-
     pub fn bound_return_position_impl_trait_in_trait_tys(
         self,
         def_id: DefId,
@@ -738,12 +733,6 @@ pub fn generator_layout_and_saved_local_names(
     }
 }
 
-impl<'tcx> TyCtxtAt<'tcx> {
-    pub fn bound_type_of(self, def_id: DefId) -> ty::EarlyBinder<Ty<'tcx>> {
-        ty::EarlyBinder(self.type_of(def_id))
-    }
-}
-
 struct OpaqueTypeExpander<'tcx> {
     // Contains the DefIds of the opaque types that are currently being
     // expanded. When we expand an opaque type we insert the DefId of
index 0bca02589bce131284365337c70dfa61bcae3596..dbba529aef7a5ea6adbf1959bd923111b42db8fd 100644 (file)
@@ -18,6 +18,9 @@ pub fn parse_statement(&self, expr_id: ExprId) -> PResult<StatementKind<'tcx>> {
             @call("mir_storage_dead", args) => {
                 Ok(StatementKind::StorageDead(self.parse_local(args[0])?))
             },
+            @call("mir_deinit", args) => {
+                Ok(StatementKind::Deinit(Box::new(self.parse_place(args[0])?)))
+            },
             @call("mir_retag", args) => {
                 Ok(StatementKind::Retag(RetagKind::Default, Box::new(self.parse_place(args[0])?)))
             },
@@ -141,12 +144,29 @@ fn parse_call(
     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),
+            @call("mir_checked", args) => {
+                parse_by_kind!(self, args[0], _, "binary op",
+                    ExprKind::Binary { op, lhs, rhs } => Ok(Rvalue::CheckedBinaryOp(
+                        *op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?))
+                    )),
+                )
+            },
+            @call("mir_len", args) => Ok(Rvalue::Len(self.parse_place(args[0])?)),
             ExprKind::Borrow { borrow_kind, arg } => Ok(
                 Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
             ),
             ExprKind::AddressOf { mutability, arg } => Ok(
                 Rvalue::AddressOf(*mutability, self.parse_place(*arg)?)
             ),
+            ExprKind::Binary { op, lhs, rhs } =>  Ok(
+                Rvalue::BinaryOp(*op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?)))
+            ),
+            ExprKind::Unary { op, arg } => Ok(
+                Rvalue::UnaryOp(*op, self.parse_operand(*arg)?)
+            ),
+            ExprKind::Repeat { value, count } => Ok(
+                Rvalue::Repeat(self.parse_operand(*value)?, *count)
+            ),
             _ => self.parse_operand(expr_id).map(Rvalue::Use),
         )
     }
index 7f81aef1c73217d57f5013678b162a4bce27b82f..ced251267d36f9deb95438e76ca848604a6b8b3a 100644 (file)
@@ -600,32 +600,56 @@ pub struct BorrowOfMovedValue<'tcx> {
 pub struct MultipleMutBorrows {
     #[primary_span]
     pub span: Span,
-    #[label]
-    pub binding_span: Span,
     #[subdiagnostic]
-    pub occurences: Vec<MultipleMutBorrowOccurence>,
-    pub name: Ident,
+    pub occurences: Vec<Conflict>,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_already_borrowed)]
+pub struct AlreadyBorrowed {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub occurences: Vec<Conflict>,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_already_mut_borrowed)]
+pub struct AlreadyMutBorrowed {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub occurences: Vec<Conflict>,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_moved_while_borrowed)]
+pub struct MovedWhileBorrowed {
+    #[primary_span]
+    pub span: Span,
+    #[subdiagnostic]
+    pub occurences: Vec<Conflict>,
 }
 
 #[derive(Subdiagnostic)]
-pub enum MultipleMutBorrowOccurence {
-    #[label(mutable_borrow)]
-    Mutable {
+pub enum Conflict {
+    #[label(mir_build_mutable_borrow)]
+    Mut {
         #[primary_span]
         span: Span,
-        name_mut: Ident,
+        name: Ident,
     },
-    #[label(immutable_borrow)]
-    Immutable {
+    #[label(mir_build_borrow)]
+    Ref {
         #[primary_span]
         span: Span,
-        name_immut: Ident,
+        name: Ident,
     },
-    #[label(moved)]
+    #[label(mir_build_moved)]
     Moved {
         #[primary_span]
         span: Span,
-        name_moved: Ident,
+        name: Ident,
     },
 }
 
index 34e637f594842687aaec93b1075bacb16eb8df0b..2640ca56b00e9764bdab912961dfa530798e3aac 100644 (file)
@@ -208,9 +208,9 @@ fn check_match(
             // Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }`
             // when the iterator is an uninhabited type. unreachable_code will trigger instead.
             hir::MatchSource::ForLoopDesugar if arms.len() == 1 => {}
-            hir::MatchSource::ForLoopDesugar | hir::MatchSource::Normal => {
-                report_arm_reachability(&cx, &report)
-            }
+            hir::MatchSource::ForLoopDesugar
+            | hir::MatchSource::Normal
+            | hir::MatchSource::FormatArgs => report_arm_reachability(&cx, &report),
             // Unreachable patterns in try and await expressions occur when one of
             // the arms are an uninhabited type. Which is OK.
             hir::MatchSource::AwaitDesugar | hir::MatchSource::TryDesugar => {}
@@ -926,58 +926,55 @@ fn check_borrow_conflicts_in_at_patterns(cx: &MatchVisitor<'_, '_, '_>, pat: &Pa
     sub.each_binding(|_, hir_id, span, name| {
         match typeck_results.extract_binding_mode(sess, hir_id, span) {
             Some(ty::BindByReference(mut_inner)) => match (mut_outer, mut_inner) {
-                (Mutability::Not, Mutability::Not) => {} // Both sides are `ref`.
-                (Mutability::Mut, Mutability::Mut) => conflicts_mut_mut.push((span, name)), // 2x `ref mut`.
-                _ => conflicts_mut_ref.push((span, name)), // `ref` + `ref mut` in either direction.
+                // Both sides are `ref`.
+                (Mutability::Not, Mutability::Not) => {}
+                // 2x `ref mut`.
+                (Mutability::Mut, Mutability::Mut) => {
+                    conflicts_mut_mut.push(Conflict::Mut { span, name })
+                }
+                (Mutability::Not, Mutability::Mut) => {
+                    conflicts_mut_ref.push(Conflict::Mut { span, name })
+                }
+                (Mutability::Mut, Mutability::Not) => {
+                    conflicts_mut_ref.push(Conflict::Ref { span, name })
+                }
             },
             Some(ty::BindByValue(_)) if is_binding_by_move(cx, hir_id) => {
-                conflicts_move.push((span, name)) // `ref mut?` + by-move conflict.
+                conflicts_move.push(Conflict::Moved { span, name }) // `ref mut?` + by-move conflict.
             }
             Some(ty::BindByValue(_)) | None => {} // `ref mut?` + by-copy is fine.
         }
     });
 
+    let report_mut_mut = !conflicts_mut_mut.is_empty();
+    let report_mut_ref = !conflicts_mut_ref.is_empty();
+    let report_move_conflict = !conflicts_move.is_empty();
+
+    let mut occurences = match mut_outer {
+        Mutability::Mut => vec![Conflict::Mut { span: binding_span, name }],
+        Mutability::Not => vec![Conflict::Ref { span: binding_span, name }],
+    };
+    occurences.extend(conflicts_mut_mut);
+    occurences.extend(conflicts_mut_ref);
+    occurences.extend(conflicts_move);
+
     // Report errors if any.
-    if !conflicts_mut_mut.is_empty() {
+    if report_mut_mut {
         // Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`.
-        let mut occurences = vec![];
-
-        for (span, name_mut) in conflicts_mut_mut {
-            occurences.push(MultipleMutBorrowOccurence::Mutable { span, name_mut });
-        }
-        for (span, name_immut) in conflicts_mut_ref {
-            occurences.push(MultipleMutBorrowOccurence::Immutable { span, name_immut });
-        }
-        for (span, name_moved) in conflicts_move {
-            occurences.push(MultipleMutBorrowOccurence::Moved { span, name_moved });
-        }
-        sess.emit_err(MultipleMutBorrows { span: pat.span, binding_span, occurences, name });
-    } else if !conflicts_mut_ref.is_empty() {
+        sess.emit_err(MultipleMutBorrows { span: pat.span, occurences });
+    } else if report_mut_ref {
         // Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse.
-        let (primary, also) = match mut_outer {
-            Mutability::Mut => ("mutable", "immutable"),
-            Mutability::Not => ("immutable", "mutable"),
+        match mut_outer {
+            Mutability::Mut => {
+                sess.emit_err(AlreadyMutBorrowed { span: pat.span, occurences });
+            }
+            Mutability::Not => {
+                sess.emit_err(AlreadyBorrowed { span: pat.span, occurences });
+            }
         };
-        let msg =
-            format!("cannot borrow value as {} because it is also borrowed as {}", also, primary);
-        let mut err = sess.struct_span_err(pat.span, &msg);
-        err.span_label(binding_span, format!("{} borrow, by `{}`, occurs here", primary, name));
-        for (span, name) in conflicts_mut_ref {
-            err.span_label(span, format!("{} borrow, by `{}`, occurs here", also, name));
-        }
-        for (span, name) in conflicts_move {
-            err.span_label(span, format!("also moved into `{}` here", name));
-        }
-        err.emit();
-    } else if !conflicts_move.is_empty() {
+    } else if report_move_conflict {
         // Report by-ref and by-move conflicts, e.g. `ref x @ y`.
-        let mut err =
-            sess.struct_span_err(pat.span, "cannot move out of value because it is borrowed");
-        err.span_label(binding_span, format!("value borrowed, by `{}`, here", name));
-        for (span, name) in conflicts_move {
-            err.span_label(span, format!("value moved into `{}` here", name));
-        }
-        err.emit();
+        sess.emit_err(MovedWhileBorrowed { span: pat.span, occurences });
     }
 }
 
index 40eefda4f076326002a270044b1526f9988110c3..da101ca7ad279e32a64967ba76fa7ef75c999d2e 100644 (file)
@@ -57,6 +57,15 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 }
 
 impl<'tcx> Visitor<'tcx> for ConstGotoOptimizationFinder<'_, 'tcx> {
+    fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) {
+        if data.is_cleanup {
+            // Because of the restrictions around control flow in cleanup blocks, we don't perform
+            // this optimization at all in such blocks.
+            return;
+        }
+        self.super_basic_block_data(block, data);
+    }
+
     fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
         let _: Option<_> = try {
             let target = terminator.kind.as_goto()?;
index 2f3c65869ef3b2ce275ef446af389d6eeb259e39..e1faa7a08d939425e0de3777b992099c66f9db7a 100644 (file)
@@ -6,7 +6,8 @@
     BinOp, Body, Constant, ConstantKind, LocalDecls, Operand, Place, ProjectionElem, Rvalue,
     SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UnOp,
 };
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, layout::TyAndLayout, ParamEnv, ParamEnvAnd, SubstsRef, Ty, TyCtxt};
+use rustc_span::symbol::{sym, Symbol};
 
 pub struct InstCombine;
 
@@ -16,7 +17,11 @@ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let ctx = InstCombineContext { tcx, local_decls: &body.local_decls };
+        let ctx = InstCombineContext {
+            tcx,
+            local_decls: &body.local_decls,
+            param_env: tcx.param_env_reveal_all_normalized(body.source.def_id()),
+        };
         for block in body.basic_blocks.as_mut() {
             for statement in block.statements.iter_mut() {
                 match statement.kind {
@@ -33,6 +38,10 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
                 &mut block.terminator.as_mut().unwrap(),
                 &mut block.statements,
             );
+            ctx.combine_intrinsic_assert(
+                &mut block.terminator.as_mut().unwrap(),
+                &mut block.statements,
+            );
         }
     }
 }
@@ -40,6 +49,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 struct InstCombineContext<'tcx, 'a> {
     tcx: TyCtxt<'tcx>,
     local_decls: &'a LocalDecls<'tcx>,
+    param_env: ParamEnv<'tcx>,
 }
 
 impl<'tcx> InstCombineContext<'tcx, '_> {
@@ -200,4 +210,76 @@ fn combine_primitive_clone(
         });
         terminator.kind = TerminatorKind::Goto { target: destination_block };
     }
+
+    fn combine_intrinsic_assert(
+        &self,
+        terminator: &mut Terminator<'tcx>,
+        _statements: &mut Vec<Statement<'tcx>>,
+    ) {
+        let TerminatorKind::Call { func, target, .. } = &mut terminator.kind  else { return; };
+        let Some(target_block) = target else { return; };
+        let func_ty = func.ty(self.local_decls, self.tcx);
+        let Some((intrinsic_name, substs)) = resolve_rust_intrinsic(self.tcx, func_ty) else {
+            return;
+        };
+        // The intrinsics we are interested in have one generic parameter
+        if substs.is_empty() {
+            return;
+        }
+        let ty = substs.type_at(0);
+
+        // Check this is a foldable intrinsic before we query the layout of our generic parameter
+        let Some(assert_panics) = intrinsic_assert_panics(intrinsic_name) else { return; };
+        let Ok(layout) = self.tcx.layout_of(self.param_env.and(ty)) else { return; };
+        if assert_panics(self.tcx, self.param_env.and(layout)) {
+            // If we know the assert panics, indicate to later opts that the call diverges
+            *target = None;
+        } else {
+            // If we know the assert does not panic, turn the call into a Goto
+            terminator.kind = TerminatorKind::Goto { target: *target_block };
+        }
+    }
+}
+
+fn intrinsic_assert_panics<'tcx>(
+    intrinsic_name: Symbol,
+) -> Option<fn(TyCtxt<'tcx>, ParamEnvAnd<'tcx, TyAndLayout<'tcx>>) -> bool> {
+    fn inhabited_predicate<'tcx>(
+        _tcx: TyCtxt<'tcx>,
+        param_env_and_layout: ParamEnvAnd<'tcx, TyAndLayout<'tcx>>,
+    ) -> bool {
+        let (_param_env, layout) = param_env_and_layout.into_parts();
+        layout.abi.is_uninhabited()
+    }
+    fn zero_valid_predicate<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        param_env_and_layout: ParamEnvAnd<'tcx, TyAndLayout<'tcx>>,
+    ) -> bool {
+        !tcx.permits_zero_init(param_env_and_layout)
+    }
+    fn mem_uninitialized_valid_predicate<'tcx>(
+        tcx: TyCtxt<'tcx>,
+        param_env_and_layout: ParamEnvAnd<'tcx, TyAndLayout<'tcx>>,
+    ) -> bool {
+        !tcx.permits_uninit_init(param_env_and_layout)
+    }
+
+    match intrinsic_name {
+        sym::assert_inhabited => Some(inhabited_predicate),
+        sym::assert_zero_valid => Some(zero_valid_predicate),
+        sym::assert_mem_uninitialized_valid => Some(mem_uninitialized_valid_predicate),
+        _ => None,
+    }
+}
+
+fn resolve_rust_intrinsic<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    func_ty: Ty<'tcx>,
+) -> Option<(Symbol, SubstsRef<'tcx>)> {
+    if let ty::FnDef(def_id, substs) = *func_ty.kind() {
+        if tcx.is_intrinsic(def_id) {
+            return Some((tcx.item_name(def_id), substs));
+        }
+    }
+    None
 }
index 4c918c6702ed9b19f3a2ed08af51506c50e17666..eda7046c748e5f52121854349a3fa6f903e502d2 100644 (file)
@@ -2372,7 +2372,7 @@ pub fn dummy_const_arg_needs_braces(
 
     /// Some special error handling for the "top-level" patterns in a match arm,
     /// `for` loop, `let`, &c. (in contrast to subpatterns within such).
-    pub(crate) fn maybe_recover_colon_colon_in_pat_typo(
+    pub(crate) fn maybe_recover_colon_colon_in_pat_typo_or_anon_enum(
         &mut self,
         mut first_pat: P<Pat>,
         expected: Expected,
@@ -2383,26 +2383,41 @@ pub(crate) fn maybe_recover_colon_colon_in_pat_typo(
         if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..))
             || !self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
         {
+            let mut snapshot_type = self.create_snapshot_for_diagnostic();
+            snapshot_type.bump(); // `:`
+            match snapshot_type.parse_ty() {
+                Err(inner_err) => {
+                    inner_err.cancel();
+                }
+                Ok(ty) => {
+                    let Err(mut err) = self.expected_one_of_not_found(&[], &[]) else {
+                        return first_pat;
+                    };
+                    err.span_label(ty.span, "specifying the type of a pattern isn't supported");
+                    self.restore_snapshot(snapshot_type);
+                    let span = first_pat.span.to(ty.span);
+                    first_pat = self.mk_pat(span, PatKind::Wild);
+                    err.emit();
+                }
+            }
             return first_pat;
         }
         // The pattern looks like it might be a path with a `::` -> `:` typo:
         // `match foo { bar:baz => {} }`
-        let span = self.token.span;
+        let colon_span = self.token.span;
         // We only emit "unexpected `:`" error here if we can successfully parse the
         // whole pattern correctly in that case.
-        let snapshot = self.create_snapshot_for_diagnostic();
+        let mut snapshot_pat = self.create_snapshot_for_diagnostic();
+        let mut snapshot_type = self.create_snapshot_for_diagnostic();
 
         // Create error for "unexpected `:`".
         match self.expected_one_of_not_found(&[], &[]) {
             Err(mut err) => {
-                self.bump(); // Skip the `:`.
-                match self.parse_pat_no_top_alt(expected) {
+                snapshot_pat.bump(); // Skip the `:`.
+                snapshot_type.bump(); // Skip the `:`.
+                match snapshot_pat.parse_pat_no_top_alt(expected) {
                     Err(inner_err) => {
-                        // Carry on as if we had not done anything, callers will emit a
-                        // reasonable error.
                         inner_err.cancel();
-                        err.cancel();
-                        self.restore_snapshot(snapshot);
                     }
                     Ok(mut pat) => {
                         // We've parsed the rest of the pattern.
@@ -2466,8 +2481,8 @@ pub(crate) fn maybe_recover_colon_colon_in_pat_typo(
                             _ => {}
                         }
                         if show_sugg {
-                            err.span_suggestion(
-                                span,
+                            err.span_suggestion_verbose(
+                                colon_span.until(self.look_ahead(1, |t| t.span)),
                                 "maybe write a path separator here",
                                 "::",
                                 Applicability::MaybeIncorrect,
@@ -2475,13 +2490,24 @@ pub(crate) fn maybe_recover_colon_colon_in_pat_typo(
                         } else {
                             first_pat = self.mk_pat(new_span, PatKind::Wild);
                         }
-                        err.emit();
+                        self.restore_snapshot(snapshot_pat);
                     }
                 }
+                match snapshot_type.parse_ty() {
+                    Err(inner_err) => {
+                        inner_err.cancel();
+                    }
+                    Ok(ty) => {
+                        err.span_label(ty.span, "specifying the type of a pattern isn't supported");
+                        self.restore_snapshot(snapshot_type);
+                        let new_span = first_pat.span.to(ty.span);
+                        first_pat = self.mk_pat(new_span, PatKind::Wild);
+                    }
+                }
+                err.emit();
             }
             _ => {
                 // Carry on as if we had not done anything. This should be unreachable.
-                self.restore_snapshot(snapshot);
             }
         };
         first_pat
index e73a17ced7deb2598f52a013189ee3392e379547..e5411538eea220ce5ff179026be98d677b08dc67 100644 (file)
@@ -116,7 +116,8 @@ fn parse_pat_allow_top_alt_inner(
 
             // Check if the user wrote `foo:bar` instead of `foo::bar`.
             if ra == RecoverColon::Yes {
-                first_pat = self.maybe_recover_colon_colon_in_pat_typo(first_pat, expected);
+                first_pat =
+                    self.maybe_recover_colon_colon_in_pat_typo_or_anon_enum(first_pat, expected);
             }
 
             if let Some(leading_vert_span) = leading_vert_span {
index 1766b0293de52a33c2eceb3254ecfe0b44e7f0af..25de0a9e75014ae019b680aedaf410e4563bcc5d 100644 (file)
@@ -11,6 +11,7 @@
     self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime,
     MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind,
 };
+use rustc_ast_pretty::pprust;
 use rustc_errors::{pluralize, struct_span_err, Applicability, PResult};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, sym, Ident};
@@ -43,17 +44,24 @@ pub(super) enum AllowPlus {
     No,
 }
 
-#[derive(PartialEq)]
+#[derive(PartialEq, Clone, Copy)]
 pub(super) enum RecoverQPath {
     Yes,
     No,
 }
 
+#[derive(PartialEq, Clone, Copy)]
 pub(super) enum RecoverQuestionMark {
     Yes,
     No,
 }
 
+#[derive(PartialEq, Clone, Copy)]
+pub(super) enum RecoverAnonEnum {
+    Yes,
+    No,
+}
+
 /// Signals whether parsing a type should recover `->`.
 ///
 /// More specifically, when parsing a function like:
@@ -86,7 +94,7 @@ fn can_recover(self, token: &TokenKind) -> bool {
 }
 
 // Is `...` (`CVarArgs`) legal at this level of type parsing?
-#[derive(PartialEq)]
+#[derive(PartialEq, Clone, Copy)]
 enum AllowCVariadic {
     Yes,
     No,
@@ -111,6 +119,7 @@ pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> {
             RecoverReturnSign::Yes,
             None,
             RecoverQuestionMark::Yes,
+            RecoverAnonEnum::No,
         )
     }
 
@@ -125,6 +134,7 @@ pub(super) fn parse_ty_with_generics_recovery(
             RecoverReturnSign::Yes,
             Some(ty_params),
             RecoverQuestionMark::Yes,
+            RecoverAnonEnum::No,
         )
     }
 
@@ -139,6 +149,7 @@ pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P<Ty>> {
             RecoverReturnSign::Yes,
             None,
             RecoverQuestionMark::Yes,
+            RecoverAnonEnum::Yes,
         )
     }
 
@@ -156,6 +167,7 @@ pub(super) fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> {
             RecoverReturnSign::Yes,
             None,
             RecoverQuestionMark::Yes,
+            RecoverAnonEnum::No,
         )
     }
 
@@ -169,6 +181,7 @@ pub(super) fn parse_as_cast_ty(&mut self) -> PResult<'a, P<Ty>> {
             RecoverReturnSign::Yes,
             None,
             RecoverQuestionMark::No,
+            RecoverAnonEnum::No,
         )
     }
 
@@ -180,6 +193,7 @@ pub(super) fn parse_no_question_mark_recover(&mut self) -> PResult<'a, P<Ty>> {
             RecoverReturnSign::Yes,
             None,
             RecoverQuestionMark::No,
+            RecoverAnonEnum::No,
         )
     }
 
@@ -192,6 +206,7 @@ pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P<Ty>> {
             RecoverReturnSign::OnlyFatArrow,
             None,
             RecoverQuestionMark::Yes,
+            RecoverAnonEnum::No,
         )
     }
 
@@ -211,6 +226,7 @@ pub(super) fn parse_ret_ty(
                 recover_return_sign,
                 None,
                 RecoverQuestionMark::Yes,
+                RecoverAnonEnum::Yes,
             )?;
             FnRetTy::Ty(ty)
         } else if recover_return_sign.can_recover(&self.token.kind) {
@@ -232,6 +248,7 @@ pub(super) fn parse_ret_ty(
                 recover_return_sign,
                 None,
                 RecoverQuestionMark::Yes,
+                RecoverAnonEnum::Yes,
             )?;
             FnRetTy::Ty(ty)
         } else {
@@ -247,6 +264,7 @@ fn parse_ty_common(
         recover_return_sign: RecoverReturnSign,
         ty_generics: Option<&Generics>,
         recover_question_mark: RecoverQuestionMark,
+        recover_anon_enum: RecoverAnonEnum,
     ) -> PResult<'a, P<Ty>> {
         let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
         maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
@@ -325,14 +343,55 @@ fn parse_ty_common(
         let mut ty = self.mk_ty(span, kind);
 
         // Try to recover from use of `+` with incorrect priority.
-        if matches!(allow_plus, AllowPlus::Yes) {
+        if allow_plus == AllowPlus::Yes {
             self.maybe_recover_from_bad_type_plus(&ty)?;
         } else {
             self.maybe_report_ambiguous_plus(impl_dyn_multi, &ty);
         }
-        if let RecoverQuestionMark::Yes = recover_question_mark {
+        if RecoverQuestionMark::Yes == recover_question_mark {
             ty = self.maybe_recover_from_question_mark(ty);
         }
+        if recover_anon_enum == RecoverAnonEnum::Yes
+            && self.check_noexpect(&token::BinOp(token::Or))
+            && self.look_ahead(1, |t| t.can_begin_type())
+        {
+            let mut pipes = vec![self.token.span];
+            let mut types = vec![ty];
+            loop {
+                if !self.eat(&token::BinOp(token::Or)) {
+                    break;
+                }
+                pipes.push(self.prev_token.span);
+                types.push(self.parse_ty_common(
+                    allow_plus,
+                    allow_c_variadic,
+                    recover_qpath,
+                    recover_return_sign,
+                    ty_generics,
+                    recover_question_mark,
+                    RecoverAnonEnum::No,
+                )?);
+            }
+            let mut err = self.struct_span_err(pipes, "anonymous enums are not supported");
+            for ty in &types {
+                err.span_label(ty.span, "");
+            }
+            err.help(&format!(
+                "create a named `enum` and use it here instead:\nenum Name {{\n{}\n}}",
+                types
+                    .iter()
+                    .enumerate()
+                    .map(|(i, t)| format!(
+                        "    Variant{}({}),",
+                        i + 1, // Lets not confuse people with zero-indexing :)
+                        pprust::to_string(|s| s.print_type(&t)),
+                    ))
+                    .collect::<Vec<_>>()
+                    .join("\n"),
+            ));
+            err.emit();
+            return Ok(self.mk_ty(lo.to(self.prev_token.span), TyKind::Err));
+        }
         if allow_qpath_recovery { self.maybe_recover_from_bad_qpath(ty) } else { Ok(ty) }
     }
 
index 7b016cadac320bcb9079fce5db9696b304377cbe..a6dfcd29762474933a31022e2f09f409d3e35865 100644 (file)
@@ -16,7 +16,6 @@
 
 pub use Alignment::*;
 pub use Count::*;
-pub use Flag::*;
 pub use Piece::*;
 pub use Position::*;
 
@@ -111,8 +110,14 @@ pub struct FormatSpec<'a> {
     pub fill: Option<char>,
     /// Optionally specified alignment.
     pub align: Alignment,
-    /// Packed version of various flags provided.
-    pub flags: u32,
+    /// The `+` or `-` flag.
+    pub sign: Option<Sign>,
+    /// The `#` flag.
+    pub alternate: bool,
+    /// The `0` flag.
+    pub zero_pad: bool,
+    /// The `x` or `X` flag. (Only for `Debug`.)
+    pub debug_hex: Option<DebugHex>,
     /// The integer precision to use.
     pub precision: Count<'a>,
     /// The span of the precision formatting flag (for diagnostics).
@@ -162,24 +167,22 @@ pub enum Alignment {
     AlignUnknown,
 }
 
-/// Various flags which can be applied to format strings. The meaning of these
-/// flags is defined by the formatters themselves.
+/// Enum for the sign flags.
 #[derive(Copy, Clone, Debug, PartialEq)]
-pub enum Flag {
-    /// A `+` will be used to denote positive numbers.
-    FlagSignPlus,
-    /// A `-` will be used to denote negative numbers. This is the default.
-    FlagSignMinus,
-    /// An alternate form will be used for the value. In the case of numbers,
-    /// this means that the number will be prefixed with the supplied string.
-    FlagAlternate,
-    /// For numbers, this means that the number will be padded with zeroes,
-    /// and the sign (`+` or `-`) will precede them.
-    FlagSignAwareZeroPad,
-    /// For Debug / `?`, format integers in lower-case hexadecimal.
-    FlagDebugLowerHex,
-    /// For Debug / `?`, format integers in upper-case hexadecimal.
-    FlagDebugUpperHex,
+pub enum Sign {
+    /// The `+` flag.
+    Plus,
+    /// The `-` flag.
+    Minus,
+}
+
+/// Enum for the debug hex flags.
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum DebugHex {
+    /// The `x` flag in `{:x?}`.
+    Lower,
+    /// The `X` flag in `{:X?}`.
+    Upper,
 }
 
 /// A count is used for the precision and width parameters of an integer, and
@@ -597,7 +600,10 @@ fn format(&mut self) -> FormatSpec<'a> {
         let mut spec = FormatSpec {
             fill: None,
             align: AlignUnknown,
-            flags: 0,
+            sign: None,
+            alternate: false,
+            zero_pad: false,
+            debug_hex: None,
             precision: CountImplied,
             precision_span: None,
             width: CountImplied,
@@ -626,13 +632,13 @@ fn format(&mut self) -> FormatSpec<'a> {
         }
         // Sign flags
         if self.consume('+') {
-            spec.flags |= 1 << (FlagSignPlus as u32);
+            spec.sign = Some(Sign::Plus);
         } else if self.consume('-') {
-            spec.flags |= 1 << (FlagSignMinus as u32);
+            spec.sign = Some(Sign::Minus);
         }
         // Alternate marker
         if self.consume('#') {
-            spec.flags |= 1 << (FlagAlternate as u32);
+            spec.alternate = true;
         }
         // Width and precision
         let mut havewidth = false;
@@ -647,7 +653,7 @@ fn format(&mut self) -> FormatSpec<'a> {
                 spec.width_span = Some(self.span(end - 1, end + 1));
                 havewidth = true;
             } else {
-                spec.flags |= 1 << (FlagSignAwareZeroPad as u32);
+                spec.zero_pad = true;
             }
         }
 
@@ -678,14 +684,14 @@ fn format(&mut self) -> FormatSpec<'a> {
         // Optional radix followed by the actual format specifier
         if self.consume('x') {
             if self.consume('?') {
-                spec.flags |= 1 << (FlagDebugLowerHex as u32);
+                spec.debug_hex = Some(DebugHex::Lower);
                 spec.ty = "?";
             } else {
                 spec.ty = "x";
             }
         } else if self.consume('X') {
             if self.consume('?') {
-                spec.flags |= 1 << (FlagDebugUpperHex as u32);
+                spec.debug_hex = Some(DebugHex::Upper);
                 spec.ty = "?";
             } else {
                 spec.ty = "X";
@@ -708,7 +714,10 @@ fn inline_asm(&mut self) -> FormatSpec<'a> {
         let mut spec = FormatSpec {
             fill: None,
             align: AlignUnknown,
-            flags: 0,
+            sign: None,
+            alternate: false,
+            zero_pad: false,
+            debug_hex: None,
             precision: CountImplied,
             precision_span: None,
             width: CountImplied,
index 2992ba845ab16aab0b3da5da04096c2978ce9900..45314e2fb5500ec4ebd395719e00d7ba68044a98 100644 (file)
@@ -10,7 +10,10 @@ fn fmtdflt() -> FormatSpec<'static> {
     return FormatSpec {
         fill: None,
         align: AlignUnknown,
-        flags: 0,
+        sign: None,
+        alternate: false,
+        zero_pad: false,
+        debug_hex: None,
         precision: CountImplied,
         width: CountImplied,
         precision_span: None,
@@ -126,7 +129,10 @@ fn format_type() {
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
-                flags: 0,
+                sign: None,
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountImplied,
                 width: CountImplied,
                 precision_span: None,
@@ -147,7 +153,10 @@ fn format_align_fill() {
             format: FormatSpec {
                 fill: None,
                 align: AlignRight,
-                flags: 0,
+                sign: None,
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountImplied,
                 width: CountImplied,
                 precision_span: None,
@@ -165,7 +174,10 @@ fn format_align_fill() {
             format: FormatSpec {
                 fill: Some('0'),
                 align: AlignLeft,
-                flags: 0,
+                sign: None,
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountImplied,
                 width: CountImplied,
                 precision_span: None,
@@ -183,7 +195,10 @@ fn format_align_fill() {
             format: FormatSpec {
                 fill: Some('*'),
                 align: AlignLeft,
-                flags: 0,
+                sign: None,
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountImplied,
                 width: CountImplied,
                 precision_span: None,
@@ -204,7 +219,10 @@ fn format_counts() {
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
-                flags: 0,
+                sign: None,
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountImplied,
                 precision_span: None,
                 width: CountIs(10),
@@ -222,7 +240,10 @@ fn format_counts() {
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
-                flags: 0,
+                sign: None,
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountIs(10),
                 precision_span: Some(InnerSpan { start: 6, end: 9 }),
                 width: CountIsParam(10),
@@ -240,7 +261,10 @@ fn format_counts() {
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
-                flags: 0,
+                sign: None,
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountIs(10),
                 precision_span: Some(InnerSpan { start: 6, end: 9 }),
                 width: CountIsParam(0),
@@ -258,7 +282,10 @@ fn format_counts() {
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
-                flags: 0,
+                sign: None,
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountIsStar(0),
                 precision_span: Some(InnerSpan { start: 3, end: 5 }),
                 width: CountImplied,
@@ -276,7 +303,10 @@ fn format_counts() {
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
-                flags: 0,
+                sign: None,
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountIsParam(10),
                 width: CountImplied,
                 precision_span: Some(InnerSpan::new(3, 7)),
@@ -294,7 +324,10 @@ fn format_counts() {
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
-                flags: 0,
+                sign: None,
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountIsName("b", InnerSpan { start: 6, end: 7 }),
                 precision_span: Some(InnerSpan { start: 5, end: 8 }),
                 width: CountIsName("a", InnerSpan { start: 3, end: 4 }),
@@ -312,7 +345,10 @@ fn format_counts() {
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
-                flags: 0,
+                sign: None,
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountIs(4),
                 precision_span: Some(InnerSpan { start: 3, end: 5 }),
                 width: CountImplied,
@@ -333,7 +369,10 @@ fn format_flags() {
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
-                flags: (1 << FlagSignMinus as u32),
+                sign: Some(Sign::Minus),
+                alternate: false,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountImplied,
                 width: CountImplied,
                 precision_span: None,
@@ -351,7 +390,10 @@ fn format_flags() {
             format: FormatSpec {
                 fill: None,
                 align: AlignUnknown,
-                flags: (1 << FlagSignPlus as u32) | (1 << FlagAlternate as u32),
+                sign: Some(Sign::Plus),
+                alternate: true,
+                zero_pad: false,
+                debug_hex: None,
                 precision: CountImplied,
                 width: CountImplied,
                 precision_span: None,
@@ -374,7 +416,10 @@ fn format_mixture() {
                 format: FormatSpec {
                     fill: None,
                     align: AlignUnknown,
-                    flags: 0,
+                    sign: None,
+                    alternate: false,
+                    zero_pad: false,
+                    debug_hex: None,
                     precision: CountImplied,
                     width: CountImplied,
                     precision_span: None,
index f9f9799d3e4f2058bf9911a23a60c22d9cf2837f..42329853259459ead163c2e4e7c70fc28084be19 100644 (file)
@@ -6,11 +6,12 @@
 
 use crate::errors::{
     self, AttrApplication, DebugVisualizerUnreadable, InvalidAttrAtCrateLevel, ObjectLifetimeErr,
-    OnlyHasEffectOn, TransparentIncompatible, UnrecognizedReprHint,
+    OnlyHasEffectOn, ProcMacroDiffArguments, ProcMacroInvalidAbi, ProcMacroMissingArguments,
+    ProcMacroTypeError, ProcMacroUnsafe, TransparentIncompatible, UnrecognizedReprHint,
 };
 use rustc_ast::{ast, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{fluent, Applicability, MultiSpan};
+use rustc_errors::{fluent, Applicability, IntoDiagnosticArg, MultiSpan};
 use rustc_expand::base::resolve_path;
 use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use rustc_hir as hir;
 use rustc_hir::{
     self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID,
 };
-use rustc_hir::{MethodKind, Target};
+use rustc_hir::{MethodKind, Target, Unsafety};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_lifetime::ObjectLifetimeDefault;
+use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{ParamEnv, TyCtxt};
 use rustc_session::lint::builtin::{
     CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, UNUSED_ATTRIBUTES,
 };
@@ -31,6 +33,7 @@
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
+use std::cell::Cell;
 use std::collections::hash_map::Entry;
 
 pub(crate) fn target_from_impl_item<'tcx>(
@@ -62,8 +65,29 @@ enum ItemLike<'tcx> {
     ForeignItem,
 }
 
+#[derive(Copy, Clone)]
+pub(crate) enum ProcMacroKind {
+    FunctionLike,
+    Derive,
+    Attribute,
+}
+
+impl IntoDiagnosticArg for ProcMacroKind {
+    fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+        match self {
+            ProcMacroKind::Attribute => "attribute proc macro",
+            ProcMacroKind::Derive => "derive proc macro",
+            ProcMacroKind::FunctionLike => "function-like proc macro",
+        }
+        .into_diagnostic_arg()
+    }
+}
+
 struct CheckAttrVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
+
+    // Whether or not this visitor should abort after finding errors
+    abort: Cell<bool>,
 }
 
 impl CheckAttrVisitor<'_> {
@@ -173,7 +197,7 @@ fn check_attributes(
                 sym::path => self.check_generic_attr(hir_id, attr, target, Target::Mod),
                 sym::plugin_registrar => self.check_plugin_registrar(hir_id, attr, target),
                 sym::macro_export => self.check_macro_export(hir_id, attr, target),
-                sym::ignore | sym::should_panic | sym::proc_macro_derive => {
+                sym::ignore | sym::should_panic => {
                     self.check_generic_attr(hir_id, attr, target, Target::Fn)
                 }
                 sym::automatically_derived => {
@@ -183,6 +207,16 @@ fn check_attributes(
                     self.check_generic_attr(hir_id, attr, target, Target::Mod)
                 }
                 sym::rustc_object_lifetime_default => self.check_object_lifetime_default(hir_id),
+                sym::proc_macro => {
+                    self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike)
+                }
+                sym::proc_macro_attribute => {
+                    self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute);
+                }
+                sym::proc_macro_derive => {
+                    self.check_generic_attr(hir_id, attr, target, Target::Fn);
+                    self.check_proc_macro(hir_id, target, ProcMacroKind::Derive)
+                }
                 _ => {}
             }
 
@@ -2063,6 +2097,103 @@ fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) {
             errors::Unused { attr_span: attr.span, note },
         );
     }
+
+    /// A best effort attempt to create an error for a mismatching proc macro signature.
+    ///
+    /// If this best effort goes wrong, it will just emit a worse error later (see #102923)
+    fn check_proc_macro(&self, hir_id: HirId, target: Target, kind: ProcMacroKind) {
+        let expected_input_count = match kind {
+            ProcMacroKind::Attribute => 2,
+            ProcMacroKind::Derive | ProcMacroKind::FunctionLike => 1,
+        };
+
+        let expected_signature = match kind {
+            ProcMacroKind::Attribute => "fn(TokenStream, TokenStream) -> TokenStream",
+            ProcMacroKind::Derive | ProcMacroKind::FunctionLike => "fn(TokenStream) -> TokenStream",
+        };
+
+        let tcx = self.tcx;
+        if target == Target::Fn {
+            let Some(tokenstream) = tcx.get_diagnostic_item(sym::TokenStream) else {return};
+            let tokenstream = tcx.type_of(tokenstream);
+
+            let id = hir_id.expect_owner();
+            let hir_sig = tcx.hir().fn_sig_by_hir_id(hir_id).unwrap();
+
+            let sig = tcx.liberate_late_bound_regions(id.to_def_id(), tcx.fn_sig(id));
+            let sig = tcx.normalize_erasing_regions(ParamEnv::empty(), sig);
+
+            // We don't currently require that the function signature is equal to
+            // `fn(TokenStream) -> TokenStream`, but instead monomorphizes to
+            // `fn(TokenStream) -> TokenStream` after some substitution of generic arguments.
+            //
+            // Properly checking this means pulling in additional `rustc` crates, so we don't.
+            let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::AsInfer };
+
+            if sig.abi != Abi::Rust {
+                tcx.sess.emit_err(ProcMacroInvalidAbi { span: hir_sig.span, abi: sig.abi.name() });
+                self.abort.set(true);
+            }
+
+            if sig.unsafety == Unsafety::Unsafe {
+                tcx.sess.emit_err(ProcMacroUnsafe { span: hir_sig.span });
+                self.abort.set(true);
+            }
+
+            let output = sig.output();
+
+            // Typecheck the output
+            if !drcx.types_may_unify(output, tokenstream) {
+                tcx.sess.emit_err(ProcMacroTypeError {
+                    span: hir_sig.decl.output.span(),
+                    found: output,
+                    kind,
+                    expected_signature,
+                });
+                self.abort.set(true);
+            }
+
+            if sig.inputs().len() < expected_input_count {
+                tcx.sess.emit_err(ProcMacroMissingArguments {
+                    expected_input_count,
+                    span: hir_sig.span,
+                    kind,
+                    expected_signature,
+                });
+                self.abort.set(true);
+            }
+
+            // Check that the inputs are correct, if there are enough.
+            if sig.inputs().len() >= expected_input_count {
+                for (arg, input) in
+                    sig.inputs().iter().zip(hir_sig.decl.inputs).take(expected_input_count)
+                {
+                    if !drcx.types_may_unify(*arg, tokenstream) {
+                        tcx.sess.emit_err(ProcMacroTypeError {
+                            span: input.span,
+                            found: *arg,
+                            kind,
+                            expected_signature,
+                        });
+                        self.abort.set(true);
+                    }
+                }
+            }
+
+            // Check that there are not too many arguments
+            let body_id = tcx.hir().body_owned_by(id.def_id);
+            let excess = tcx.hir().body(body_id).params.get(expected_input_count..);
+            if let Some(excess @ [begin @ end] | excess @ [begin, .., end]) = excess {
+                tcx.sess.emit_err(ProcMacroDiffArguments {
+                    span: begin.span.to(end.span),
+                    count: excess.len(),
+                    kind,
+                    expected_signature,
+                });
+                self.abort.set(true);
+            }
+        }
+    }
 }
 
 impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
@@ -2225,12 +2356,15 @@ fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>)
 }
 
 fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
-    let check_attr_visitor = &mut CheckAttrVisitor { tcx };
+    let check_attr_visitor = &mut CheckAttrVisitor { tcx, abort: Cell::new(false) };
     tcx.hir().visit_item_likes_in_module(module_def_id, check_attr_visitor);
     if module_def_id.is_top_level_module() {
         check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None);
         check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs());
     }
+    if check_attr_visitor.abort.get() {
+        tcx.sess.abort_if_errors()
+    }
 }
 
 pub(crate) fn provide(providers: &mut Providers) {
index aa726d6cd92aad0b9a7ce3374f23c64c944fe7d1..dd8c646a43c82e837b0393155f7660931147e0d1 100644 (file)
@@ -48,7 +48,7 @@ fn required_feature_gates(self) -> Option<&'static [Symbol]> {
             Self::Match(TryDesugar) => &[sym::const_try],
 
             // All other expressions are allowed.
-            Self::Loop(Loop | While) | Self::Match(Normal) => &[],
+            Self::Loop(Loop | While) | Self::Match(Normal | FormatArgs) => &[],
         };
 
         Some(gates)
index 9c6519ea4bb24be91a133b22d716ca376593ae4d..9e05ad22e624172681d1b249710a71f669297cbf 100644 (file)
@@ -12,6 +12,7 @@
 use rustc_middle::ty::{MainDefinition, Ty};
 use rustc_span::{Span, Symbol, DUMMY_SP};
 
+use crate::check_attr::ProcMacroKind;
 use crate::lang_items::Duplicate;
 
 #[derive(Diagnostic)]
@@ -1515,3 +1516,52 @@ pub struct ChangeFieldsToBeOfUnitType {
     #[suggestion_part(code = "()")]
     pub spans: Vec<Span>,
 }
+
+#[derive(Diagnostic)]
+#[diag(passes_proc_macro_typeerror)]
+#[note]
+pub(crate) struct ProcMacroTypeError<'tcx> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub found: Ty<'tcx>,
+    pub kind: ProcMacroKind,
+    pub expected_signature: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_proc_macro_diff_arg_count)]
+pub(crate) struct ProcMacroDiffArguments {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub count: usize,
+    pub kind: ProcMacroKind,
+    pub expected_signature: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_proc_macro_missing_args)]
+pub(crate) struct ProcMacroMissingArguments {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub expected_input_count: usize,
+    pub kind: ProcMacroKind,
+    pub expected_signature: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_proc_macro_invalid_abi)]
+pub(crate) struct ProcMacroInvalidAbi {
+    #[primary_span]
+    pub span: Span,
+    pub abi: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(passes_proc_macro_unsafe)]
+pub(crate) struct ProcMacroUnsafe {
+    #[primary_span]
+    pub span: Span,
+}
index b86d2316820cec75ab3fa744079775fa22151d6c..d1b896e940e6e7d6f054b22c2ac7bc0f98e8b592 100644 (file)
@@ -567,7 +567,7 @@ fn visit_expr(&mut self, e: &'v ast::Expr) {
                 Box, Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let,
                 If, While, ForLoop, Loop, Match, Closure, Block, Async, Await, TryBlock, Assign,
                 AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret,
-                InlineAsm, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, IncludedBytes, Err
+                InlineAsm, FormatArgs, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, IncludedBytes, Err
             ]
         );
         ast_visit::walk_expr(self, e)
index 6d448433ee6dbc940bdcde726b3a9f25efbe8997..37beff37c1fb9d988c33ae968afa86fb96370603 100644 (file)
@@ -227,20 +227,27 @@ fn make_base_error(
                     && let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt()
                     && let Some(items) = self.diagnostic_metadata.current_impl_items
                     && let Some(item) = items.iter().find(|i| {
-                        if let AssocItemKind::Fn(_) = &i.kind && i.ident.name == item_str.name
+                        if let AssocItemKind::Fn(..) | AssocItemKind::Const(..) = &i.kind
+                            && i.ident.name == item_str.name
                         {
                             debug!(?item_str.name);
                             return true
                         }
                         false
                     })
-                    && let AssocItemKind::Fn(fn_) = &item.kind
                 {
-                    debug!(?fn_);
-                    let self_sugg = if fn_.sig.decl.has_self() { "self." } else { "Self::" };
+                    let self_sugg = match &item.kind {
+                        AssocItemKind::Fn(fn_) if fn_.sig.decl.has_self() => "self.",
+                        _ => "Self::",
+                    };
+
                     Some((
                         item_span.shrink_to_lo(),
-                        "consider using the associated function",
+                        match &item.kind {
+                            AssocItemKind::Fn(..) => "consider using the associated function",
+                            AssocItemKind::Const(..) => "consider using the associated constant",
+                            _ => unreachable!("item kind was filtered above"),
+                        },
                         self_sugg.to_string()
                     ))
                 } else {
index 586454f76574c5b2ad62a7075674da3e9da39cd2..db95b8bca2f8ce78791f77dfd1cb801dd9151c50 100644 (file)
@@ -864,18 +864,6 @@ pub enum CrateType {
     ProcMacro,
 }
 
-impl CrateType {
-    /// When generated, is this crate type an archive?
-    pub fn is_archive(&self) -> bool {
-        match *self {
-            CrateType::Rlib | CrateType::Staticlib => true,
-            CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
-                false
-            }
-        }
-    }
-}
-
 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
 pub enum Passes {
     Some(Vec<String>),
@@ -957,6 +945,7 @@ fn default_configuration(sess: &Session) -> CrateConfig {
     if sess.target.has_thread_local {
         ret.insert((sym::target_thread_local, None));
     }
+    let mut has_atomic = false;
     for (i, align) in [
         (8, layout.i8_align.abi),
         (16, layout.i16_align.abi),
@@ -965,6 +954,7 @@ fn default_configuration(sess: &Session) -> CrateConfig {
         (128, layout.i128_align.abi),
     ] {
         if i >= min_atomic_width && i <= max_atomic_width {
+            has_atomic = true;
             let mut insert_atomic = |s, align: Align| {
                 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
                 if atomic_cas {
@@ -981,6 +971,12 @@ fn default_configuration(sess: &Session) -> CrateConfig {
             }
         }
     }
+    if sess.is_nightly_build() && has_atomic {
+        ret.insert((sym::target_has_atomic_load_store, None));
+        if atomic_cas {
+            ret.insert((sym::target_has_atomic, None));
+        }
+    }
 
     let panic_strategy = sess.panic_strategy();
     ret.insert((sym::panic, Some(panic_strategy.desc_symbol())));
index 7597b8d126a9ceb55375ecdb2f9f523cd756e093..30ca0b8060d22b2bdfbd5668aafe03c41ff20109 100644 (file)
         Target,
         ToOwned,
         ToString,
+        TokenStream,
         Try,
         TryCaptureGeneric,
         TryCapturePrintable,
         forbid,
         forget,
         format,
+        format_alignment,
         format_args,
         format_args_capture,
         format_args_macro,
         format_args_nl,
+        format_argument,
+        format_arguments,
+        format_count,
         format_macro,
+        format_placeholder,
+        format_unsafe_arg,
         freeze,
         freg,
         frem_fast,
index 4a2d39cc70023bbb81b49c3ba06413273b85e9f0..247256f076ba9b195c6cbe1286387b4ba7a9c3f8 100644 (file)
@@ -39,7 +39,7 @@ fn should_use_fp_conv_helper<'a, Ty, C>(
 {
     match arg_layout.abi {
         Abi::Scalar(scalar) => match scalar.primitive() {
-            abi::Int(..) | abi::Pointer => {
+            abi::Int(..) | abi::Pointer(_) => {
                 if arg_layout.size.bits() > xlen {
                     return Err(CannotUseFpConv);
                 }
index 3b8c867d35ba37b3a06e41b64b90123c19f514d6..a0730fbb650dc9b4527882bbe232afa1ed17201b 100644 (file)
@@ -346,7 +346,7 @@ pub fn homogeneous_aggregate<C>(&self, cx: &C) -> Result<HomogeneousAggregate, H
             // The primitive for this algorithm.
             Abi::Scalar(scalar) => {
                 let kind = match scalar.primitive() {
-                    abi::Int(..) | abi::Pointer => RegKind::Integer,
+                    abi::Int(..) | abi::Pointer(_) => RegKind::Integer,
                     abi::F32 | abi::F64 => RegKind::Float,
                 };
                 Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }))
index 34280d38e3406a7bef5f4e00839b993f88f10eec..d90dce2a08785cbd2e6995bfb5f16fd9acc77f7d 100644 (file)
@@ -45,7 +45,7 @@ fn should_use_fp_conv_helper<'a, Ty, C>(
 {
     match arg_layout.abi {
         Abi::Scalar(scalar) => match scalar.primitive() {
-            abi::Int(..) | abi::Pointer => {
+            abi::Int(..) | abi::Pointer(_) => {
                 if arg_layout.size.bits() > xlen {
                     return Err(CannotUseFpConv);
                 }
index c8b6ac5ae25b2eb60152c2f3ae166471d0bb3f58..cbed5b4afc134931a0ba5851f90218399775b5b4 100644 (file)
@@ -20,7 +20,7 @@ fn arg_scalar<C>(cx: &C, scalar: &Scalar, offset: Size, mut data: Sdata) -> Sdat
 {
     let dl = cx.data_layout();
 
-    if !scalar.primitive().is_float() {
+    if !matches!(scalar.primitive(), abi::F32 | abi::F64) {
         return data;
     }
 
@@ -83,11 +83,11 @@ fn arg_scalar_pair<C>(
         (abi::F32, _) => offset += Reg::f32().size,
         (_, abi::F64) => offset += Reg::f64().size,
         (abi::Int(i, _signed), _) => offset += i.size(),
-        (abi::Pointer, _) => offset += Reg::i64().size,
+        (abi::Pointer(_), _) => offset += Reg::i64().size,
         _ => {}
     }
 
-    if (offset.bytes() % 4) != 0 && scalar2.primitive().is_float() {
+    if (offset.bytes() % 4) != 0 && matches!(scalar2.primitive(), abi::F32 | abi::F64) {
         offset += Size::from_bytes(4 - (offset.bytes() % 4));
     }
     data = arg_scalar(cx, scalar2, offset, data);
index c0c071a614f5058808e7bbd11384287ca9139e6e..9427f27d1b7bb327893a287c1d83db37822159b3 100644 (file)
@@ -50,7 +50,7 @@ fn classify<'a, Ty, C>(
             Abi::Uninhabited => return Ok(()),
 
             Abi::Scalar(scalar) => match scalar.primitive() {
-                abi::Int(..) | abi::Pointer => Class::Int,
+                abi::Int(..) | abi::Pointer(_) => Class::Int,
                 abi::F32 | abi::F64 => Class::Sse,
             },
 
index 88a0a1f8ecfdedafd60a8d9f6f516f488f06ca79..39761baf1bc2919401d823dc4d17aaae56d59195 100644 (file)
@@ -129,7 +129,7 @@ pub fn is_single_fp_element<C>(self, cx: &C) -> bool
         C: HasDataLayout,
     {
         match self.abi {
-            Abi::Scalar(scalar) => scalar.primitive().is_float(),
+            Abi::Scalar(scalar) => matches!(scalar.primitive(), F32 | F64),
             Abi::Aggregate { .. } => {
                 if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
                     self.field(cx, 0).is_single_fp_element(cx)
index 0b642fcba281249da01b21d4af4ece7fe96c2636..d23b550621e17421ce179a63a98a4445ec4f3402 100644 (file)
@@ -138,6 +138,16 @@ fn consider_builtin_pointee_candidate(
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx>;
+
+    fn consider_builtin_future_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx>;
+
+    fn consider_builtin_generator_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx>;
 }
 
 impl<'tcx> EvalCtxt<'_, 'tcx> {
@@ -266,6 +276,10 @@ fn assemble_builtin_impl_candidates<G: GoalKind<'tcx>>(
             G::consider_builtin_tuple_candidate(self, goal)
         } else if lang_items.pointee_trait() == Some(trait_def_id) {
             G::consider_builtin_pointee_candidate(self, goal)
+        } else if lang_items.future_trait() == Some(trait_def_id) {
+            G::consider_builtin_future_candidate(self, goal)
+        } else if lang_items.gen_trait() == Some(trait_def_id) {
+            G::consider_builtin_generator_candidate(self, goal)
         } else {
             Err(NoSolution)
         };
@@ -321,9 +335,10 @@ fn assemble_alias_bound_candidates<G: GoalKind<'tcx>>(
             | ty::Tuple(_)
             | ty::Param(_)
             | ty::Placeholder(..)
-            | ty::Infer(_)
+            | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
             | ty::Error(_) => return,
-            ty::Bound(..) => bug!("unexpected bound type: {goal:?}"),
+            ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
+            | ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"),
             ty::Alias(_, alias_ty) => alias_ty,
         };
 
@@ -371,9 +386,10 @@ fn assemble_object_bound_candidates<G: GoalKind<'tcx>>(
             | ty::Tuple(_)
             | ty::Param(_)
             | ty::Placeholder(..)
-            | ty::Infer(_)
+            | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
             | ty::Error(_) => return,
-            ty::Bound(..) => bug!("unexpected bound type: {goal:?}"),
+            ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
+            | ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"),
             ty::Dynamic(bounds, ..) => bounds,
         };
 
index d59fa71406c31197c75a4bedbe1545463f302b8a..278024b22760a754a8634d5cd16b58f583948da6 100644 (file)
@@ -1,13 +1,14 @@
 use std::mem;
 
-use super::{Certainty, InferCtxtEvalExt};
-use rustc_infer::{
-    infer::InferCtxt,
-    traits::{
-        query::NoSolution, FulfillmentError, FulfillmentErrorCode, PredicateObligation,
-        SelectionError, TraitEngine,
-    },
+use rustc_infer::infer::InferCtxt;
+use rustc_infer::traits::{
+    query::NoSolution, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
+    PredicateObligation, SelectionError, TraitEngine,
 };
+use rustc_middle::ty;
+use rustc_middle::ty::error::{ExpectedFound, TypeError};
+
+use super::{Certainty, InferCtxtEvalExt};
 
 /// A trait engine using the new trait solver.
 ///
@@ -70,9 +71,55 @@ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentE
                     Err(NoSolution) => {
                         errors.push(FulfillmentError {
                             obligation: obligation.clone(),
-                            code: FulfillmentErrorCode::CodeSelectionError(
-                                SelectionError::Unimplemented,
-                            ),
+                            code: match goal.predicate.kind().skip_binder() {
+                                ty::PredicateKind::Clause(ty::Clause::Projection(_)) => {
+                                    FulfillmentErrorCode::CodeProjectionError(
+                                        // FIXME: This could be a `Sorts` if the term is a type
+                                        MismatchedProjectionTypes { err: TypeError::Mismatch },
+                                    )
+                                }
+                                ty::PredicateKind::Subtype(pred) => {
+                                    let (a, b) = infcx.replace_bound_vars_with_placeholders(
+                                        goal.predicate.kind().rebind((pred.a, pred.b)),
+                                    );
+                                    let expected_found = ExpectedFound::new(true, a, b);
+                                    FulfillmentErrorCode::CodeSubtypeError(
+                                        expected_found,
+                                        TypeError::Sorts(expected_found),
+                                    )
+                                }
+                                ty::PredicateKind::Coerce(pred) => {
+                                    let (a, b) = infcx.replace_bound_vars_with_placeholders(
+                                        goal.predicate.kind().rebind((pred.a, pred.b)),
+                                    );
+                                    let expected_found = ExpectedFound::new(false, a, b);
+                                    FulfillmentErrorCode::CodeSubtypeError(
+                                        expected_found,
+                                        TypeError::Sorts(expected_found),
+                                    )
+                                }
+                                ty::PredicateKind::ConstEquate(a, b) => {
+                                    let (a, b) = infcx.replace_bound_vars_with_placeholders(
+                                        goal.predicate.kind().rebind((a, b)),
+                                    );
+                                    let expected_found = ExpectedFound::new(true, a, b);
+                                    FulfillmentErrorCode::CodeConstEquateError(
+                                        expected_found,
+                                        TypeError::ConstMismatch(expected_found),
+                                    )
+                                }
+                                ty::PredicateKind::Clause(_)
+                                | ty::PredicateKind::WellFormed(_)
+                                | ty::PredicateKind::ObjectSafe(_)
+                                | ty::PredicateKind::ClosureKind(_, _, _)
+                                | ty::PredicateKind::ConstEvaluatable(_)
+                                | ty::PredicateKind::TypeWellFormedFromEnv(_)
+                                | ty::PredicateKind::Ambiguous => {
+                                    FulfillmentErrorCode::CodeSelectionError(
+                                        SelectionError::Unimplemented,
+                                    )
+                                }
+                            },
                             root_obligation: obligation,
                         });
                         continue;
index 70f094014453edfcca6960ef8a09c64a5ab4798f..f44648c95d742530298274dc3467dc6645e127e6 100644 (file)
@@ -277,12 +277,15 @@ fn compute_goal(&mut self, goal: Goal<'tcx, ty::Predicate<'tcx>>) -> QueryResult
                         param_env,
                         predicate: (def_id, substs, kind),
                     }),
+                ty::PredicateKind::ObjectSafe(trait_def_id) => {
+                    self.compute_object_safe_goal(trait_def_id)
+                }
+                ty::PredicateKind::WellFormed(arg) => {
+                    self.compute_well_formed_goal(Goal { param_env, predicate: arg })
+                }
                 ty::PredicateKind::Ambiguous => self.make_canonical_response(Certainty::AMBIGUOUS),
                 // FIXME: implement these predicates :)
-                ty::PredicateKind::WellFormed(_)
-                | ty::PredicateKind::ObjectSafe(_)
-                | ty::PredicateKind::ConstEvaluatable(_)
-                | ty::PredicateKind::ConstEquate(_, _) => {
+                ty::PredicateKind::ConstEvaluatable(_) | ty::PredicateKind::ConstEquate(_, _) => {
                     self.make_canonical_response(Certainty::Yes)
                 }
                 ty::PredicateKind::TypeWellFormedFromEnv(..) => {
@@ -362,6 +365,32 @@ fn compute_closure_kind_goal(
             Err(NoSolution)
         }
     }
+
+    fn compute_object_safe_goal(&mut self, trait_def_id: DefId) -> QueryResult<'tcx> {
+        if self.tcx().is_object_safe(trait_def_id) {
+            self.make_canonical_response(Certainty::Yes)
+        } else {
+            Err(NoSolution)
+        }
+    }
+
+    fn compute_well_formed_goal(
+        &mut self,
+        goal: Goal<'tcx, ty::GenericArg<'tcx>>,
+    ) -> QueryResult<'tcx> {
+        self.infcx.probe(|_| {
+            match crate::traits::wf::unnormalized_obligations(
+                self.infcx,
+                goal.param_env,
+                goal.predicate,
+            ) {
+                Some(obligations) => self.evaluate_all_and_make_canonical_response(
+                    obligations.into_iter().map(|o| o.into()).collect(),
+                ),
+                None => self.make_canonical_response(Certainty::AMBIGUOUS),
+            }
+        })
+    }
 }
 
 impl<'tcx> EvalCtxt<'_, 'tcx> {
index e5072d8e2d15216adfb84e40a508470ddaaaef8d..b583705ac43693a6619c1776ce1df2efe37bea02 100644 (file)
@@ -16,7 +16,7 @@
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{ProjectionPredicate, TypeSuperVisitable, TypeVisitor};
 use rustc_middle::ty::{ToPredicate, TypeVisitable};
-use rustc_span::DUMMY_SP;
+use rustc_span::{sym, DUMMY_SP};
 use std::iter;
 use std::ops::ControlFlow;
 
@@ -427,7 +427,7 @@ fn consider_builtin_pointee_candidate(
                         .subst(tcx, &[ty::GenericArg::from(goal.predicate.self_ty())])
                 }
 
-                ty::Infer(ty::TyVar(..)) | ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
+                ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
                     // FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints.
                     let sized_predicate = ty::Binder::dummy(tcx.at(DUMMY_SP).mk_trait_ref(
                         LangItem::Sized,
@@ -470,7 +470,9 @@ fn consider_builtin_pointee_candidate(
                     }
                 },
 
-                ty::Infer(ty::FreshTy(..) | ty::FreshIntTy(..) | ty::FreshFloatTy(..))
+                ty::Infer(
+                    ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_),
+                )
                 | ty::Bound(..) => bug!(
                     "unexpected self ty `{:?}` when normalizing `<T as Pointee>::Metadata`",
                     goal.predicate.self_ty()
@@ -482,6 +484,73 @@ fn consider_builtin_pointee_candidate(
             ecx.evaluate_all_and_make_canonical_response(nested_goals)
         })
     }
+
+    fn consider_builtin_future_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        let self_ty = goal.predicate.self_ty();
+        let ty::Generator(def_id, substs, _) = *self_ty.kind() else {
+            return Err(NoSolution);
+        };
+
+        // Generators are not futures unless they come from `async` desugaring
+        let tcx = ecx.tcx();
+        if !tcx.generator_is_async(def_id) {
+            return Err(NoSolution);
+        }
+
+        let term = substs.as_generator().return_ty().into();
+
+        Self::consider_assumption(
+            ecx,
+            goal,
+            ty::Binder::dummy(ty::ProjectionPredicate {
+                projection_ty: ecx.tcx().mk_alias_ty(goal.predicate.def_id(), [self_ty]),
+                term,
+            })
+            .to_predicate(tcx),
+        )
+    }
+
+    fn consider_builtin_generator_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        let self_ty = goal.predicate.self_ty();
+        let ty::Generator(def_id, substs, _) = *self_ty.kind() else {
+            return Err(NoSolution);
+        };
+
+        // `async`-desugared generators do not implement the generator trait
+        let tcx = ecx.tcx();
+        if tcx.generator_is_async(def_id) {
+            return Err(NoSolution);
+        }
+
+        let generator = substs.as_generator();
+
+        let name = tcx.associated_item(goal.predicate.def_id()).name;
+        let term = if name == sym::Return {
+            generator.return_ty().into()
+        } else if name == sym::Yield {
+            generator.yield_ty().into()
+        } else {
+            bug!("unexpected associated item `<{self_ty} as Generator>::{name}`")
+        };
+
+        Self::consider_assumption(
+            ecx,
+            goal,
+            ty::Binder::dummy(ty::ProjectionPredicate {
+                projection_ty: ecx
+                    .tcx()
+                    .mk_alias_ty(goal.predicate.def_id(), [self_ty, generator.resume_ty()]),
+                term,
+            })
+            .to_predicate(tcx),
+        )
+    }
 }
 
 /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
index 67bd2495665465d254ec83cc927ce42b0471c975..d74857dc4b4803bac6b418941d6e9122dd1fae3b 100644 (file)
@@ -192,6 +192,50 @@ fn consider_builtin_pointee_candidate(
     ) -> QueryResult<'tcx> {
         ecx.make_canonical_response(Certainty::Yes)
     }
+
+    fn consider_builtin_future_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        let ty::Generator(def_id, _, _) = *goal.predicate.self_ty().kind() else {
+            return Err(NoSolution);
+        };
+
+        // Generators are not futures unless they come from `async` desugaring
+        let tcx = ecx.tcx();
+        if !tcx.generator_is_async(def_id) {
+            return Err(NoSolution);
+        }
+
+        // Async generator unconditionally implement `Future`
+        ecx.make_canonical_response(Certainty::Yes)
+    }
+
+    fn consider_builtin_generator_candidate(
+        ecx: &mut EvalCtxt<'_, 'tcx>,
+        goal: Goal<'tcx, Self>,
+    ) -> QueryResult<'tcx> {
+        let self_ty = goal.predicate.self_ty();
+        let ty::Generator(def_id, substs, _) = *self_ty.kind() else {
+            return Err(NoSolution);
+        };
+
+        // `async`-desugared generators do not implement the generator trait
+        let tcx = ecx.tcx();
+        if tcx.generator_is_async(def_id) {
+            return Err(NoSolution);
+        }
+
+        let generator = substs.as_generator();
+        Self::consider_assumption(
+            ecx,
+            goal,
+            ty::Binder::dummy(
+                tcx.mk_trait_ref(goal.predicate.def_id(), [self_ty, generator.resume_ty()]),
+            )
+            .to_predicate(tcx),
+        )
+    }
 }
 
 impl<'tcx> EvalCtxt<'_, 'tcx> {
index a11cd13cb0856b4df3ace3c1261baf9a69d9d4dc..c2a19372f18c4f97e352ec7d426820fc2901752c 100644 (file)
@@ -24,15 +24,16 @@ pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
         | ty::Never
         | ty::Char => Ok(vec![]),
 
-        ty::Placeholder(..)
-        | ty::Dynamic(..)
+        ty::Dynamic(..)
         | ty::Param(..)
         | ty::Foreign(..)
         | ty::Alias(ty::Projection, ..)
-        | ty::Bound(..)
-        | ty::Infer(ty::TyVar(_)) => Err(NoSolution),
+        | ty::Placeholder(..) => Err(NoSolution),
 
-        ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
+        ty::Bound(..)
+        | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+            bug!("unexpected type `{ty}`")
+        }
 
         ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => {
             Ok(vec![element_ty])
@@ -99,11 +100,12 @@ pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
         | ty::Foreign(..)
         | ty::Alias(..)
         | ty::Param(_)
-        | ty::Infer(ty::TyVar(_)) => Err(NoSolution),
+        | ty::Placeholder(..) => Err(NoSolution),
 
-        ty::Placeholder(..)
-        | ty::Bound(..)
-        | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
+        ty::Bound(..)
+        | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+            bug!("unexpected type `{ty}`")
+        }
 
         ty::Tuple(tys) => Ok(tys.to_vec()),
 
@@ -148,11 +150,12 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
         | ty::Adt(_, _)
         | ty::Alias(_, _)
         | ty::Param(_)
-        | ty::Infer(ty::TyVar(_)) => Err(NoSolution),
+        | ty::Placeholder(..) => Err(NoSolution),
 
-        ty::Placeholder(..)
-        | ty::Bound(..)
-        | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!(),
+        ty::Bound(..)
+        | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+            bug!("unexpected type `{ty}`")
+        }
 
         ty::Tuple(tys) => Ok(tys.to_vec()),
 
@@ -173,6 +176,7 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
     }
 }
 
+// Returns a binder of the tupled inputs types and output type from a builtin callable type.
 pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
     tcx: TyCtxt<'tcx>,
     self_ty: Ty<'tcx>,
@@ -215,9 +219,13 @@ pub(crate) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
         | ty::Tuple(_)
         | ty::Alias(_, _)
         | ty::Param(_)
-        | ty::Placeholder(_)
-        | ty::Bound(_, _)
-        | ty::Infer(_)
+        | ty::Placeholder(..)
+        | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
         | ty::Error(_) => Err(NoSolution),
+
+        ty::Bound(..)
+        | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+            bug!("unexpected type `{self_ty}`")
+        }
     }
 }
index f90da95d51668b56cfbb582cbae2231ef6db371f..1d23634b6aacf58762466cd987d387d2ea743525 100644 (file)
@@ -38,6 +38,8 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::LateBoundRegionConversionTime;
+use rustc_infer::traits::TraitEngine;
+use rustc_infer::traits::TraitEngineExt;
 use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
@@ -47,6 +49,7 @@
 use rustc_middle::ty::SubstsRef;
 use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
 use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitable};
+use rustc_session::config::TraitSolver;
 use rustc_span::symbol::sym;
 
 use std::cell::{Cell, RefCell};
@@ -544,10 +547,14 @@ pub fn evaluate_root_obligation(
         obligation: &PredicateObligation<'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
         self.evaluation_probe(|this| {
-            this.evaluate_predicate_recursively(
-                TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
-                obligation.clone(),
-            )
+            if this.tcx().sess.opts.unstable_opts.trait_solver != TraitSolver::Next {
+                this.evaluate_predicate_recursively(
+                    TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
+                    obligation.clone(),
+                )
+            } else {
+                this.evaluate_predicates_recursively_in_new_solver([obligation.clone()])
+            }
         })
     }
 
@@ -586,18 +593,40 @@ fn evaluate_predicates_recursively<'o, I>(
     where
         I: IntoIterator<Item = PredicateObligation<'tcx>> + std::fmt::Debug,
     {
-        let mut result = EvaluatedToOk;
-        for obligation in predicates {
-            let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
-            if let EvaluatedToErr = eval {
-                // fast-path - EvaluatedToErr is the top of the lattice,
-                // so we don't need to look on the other predicates.
-                return Ok(EvaluatedToErr);
-            } else {
-                result = cmp::max(result, eval);
+        if self.tcx().sess.opts.unstable_opts.trait_solver != TraitSolver::Next {
+            let mut result = EvaluatedToOk;
+            for obligation in predicates {
+                let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?;
+                if let EvaluatedToErr = eval {
+                    // fast-path - EvaluatedToErr is the top of the lattice,
+                    // so we don't need to look on the other predicates.
+                    return Ok(EvaluatedToErr);
+                } else {
+                    result = cmp::max(result, eval);
+                }
             }
+            Ok(result)
+        } else {
+            self.evaluate_predicates_recursively_in_new_solver(predicates)
         }
-        Ok(result)
+    }
+
+    /// Evaluates the predicates using the new solver when `-Ztrait-solver=next` is enabled
+    fn evaluate_predicates_recursively_in_new_solver(
+        &mut self,
+        predicates: impl IntoIterator<Item = PredicateObligation<'tcx>>,
+    ) -> Result<EvaluationResult, OverflowError> {
+        let mut fulfill_cx = crate::solve::FulfillmentCtxt::new();
+        fulfill_cx.register_predicate_obligations(self.infcx, predicates);
+        // True errors
+        if !fulfill_cx.select_where_possible(self.infcx).is_empty() {
+            return Ok(EvaluatedToErr);
+        }
+        if !fulfill_cx.select_all_or_error(self.infcx).is_empty() {
+            return Ok(EvaluatedToAmbig);
+        }
+        // Regions and opaques are handled in the `evaluation_probe` by looking at the snapshot
+        Ok(EvaluatedToOk)
     }
 
     #[instrument(
index d9556848099f122ead5b1a3079d41b0a4fd7f8f1..767e31ddf781a9666bde067a1162e10ada3f478a 100644 (file)
@@ -4,8 +4,8 @@
 use rustc_hir::lang_items::LangItem;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable};
-use rustc_span::def_id::{DefId, LocalDefId};
-use rustc_span::Span;
+use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
+use rustc_span::{Span, DUMMY_SP};
 
 use std::iter;
 /// Returns the set of obligations needed to make `arg` well-formed.
@@ -75,6 +75,34 @@ pub fn obligations<'tcx>(
     Some(result)
 }
 
+/// Compute the predicates that are required for a type to be well-formed.
+///
+/// This is only intended to be used in the new solver, since it does not
+/// take into account recursion depth or proper error-reporting spans.
+pub fn unnormalized_obligations<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    arg: GenericArg<'tcx>,
+) -> Option<Vec<traits::PredicateObligation<'tcx>>> {
+    if let ty::GenericArgKind::Lifetime(..) = arg.unpack() {
+        return Some(vec![]);
+    }
+
+    debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg));
+
+    let mut wf = WfPredicates {
+        tcx: infcx.tcx,
+        param_env,
+        body_id: CRATE_DEF_ID,
+        span: DUMMY_SP,
+        out: vec![],
+        recursion_depth: 0,
+        item: None,
+    };
+    wf.compute(arg);
+    Some(wf.out)
+}
+
 /// Returns the obligations that make this trait reference
 /// well-formed. For example, if there is a trait `Set` defined like
 /// `trait Set<K:Eq>`, then the trait reference `Foo: Set<Bar>` is WF
index 91a505a72fae7a6be74b31e2b2ff0909af29b877..e47e68e0670b9475a19080561dade3f4098940c3 100644 (file)
@@ -244,7 +244,7 @@ fn adjust_for_rust_scalar<'tcx>(
     }
 
     // Only pointer types handled below.
-    let Scalar::Initialized { value: Pointer, valid_range} = scalar else { return };
+    let Scalar::Initialized { value: Pointer(_), valid_range} = scalar else { return };
 
     if !valid_range.contains(0) {
         attrs.set(ArgAttribute::NonNull);
@@ -479,7 +479,7 @@ fn fn_abi_adjust_for_abi<'tcx>(
             }
 
             let size = arg.layout.size;
-            if arg.layout.is_unsized() || size > Pointer.size(cx) {
+            if arg.layout.is_unsized() || size > Pointer(AddressSpace::DATA).size(cx) {
                 arg.make_indirect();
             } else {
                 // We want to pass small aggregates as immediates, but using
index 6aa016133ca598926fffa1b2823962b11332da92..0f25579c7bfa19f8fc609ce9adabd167f9e37116 100644 (file)
@@ -134,7 +134,7 @@ fn layout_of_uncached<'tcx>(
             ty::FloatTy::F64 => F64,
         }),
         ty::FnPtr(_) => {
-            let mut ptr = scalar_unit(Pointer);
+            let mut ptr = scalar_unit(Pointer(dl.instruction_address_space));
             ptr.valid_range_mut().start = 1;
             tcx.intern_layout(LayoutS::scalar(cx, ptr))
         }
@@ -144,7 +144,7 @@ fn layout_of_uncached<'tcx>(
 
         // Potentially-wide pointers.
         ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
-            let mut data_ptr = scalar_unit(Pointer);
+            let mut data_ptr = scalar_unit(Pointer(AddressSpace::DATA));
             if !ty.is_unsafe_ptr() {
                 data_ptr.valid_range_mut().start = 1;
             }
@@ -178,7 +178,7 @@ fn layout_of_uncached<'tcx>(
                     }
                     ty::Slice(_) | ty::Str => scalar_unit(Int(dl.ptr_sized_integer(), false)),
                     ty::Dynamic(..) => {
-                        let mut vtable = scalar_unit(Pointer);
+                        let mut vtable = scalar_unit(Pointer(AddressSpace::DATA));
                         vtable.valid_range_mut().start = 1;
                         vtable
                     }
@@ -195,7 +195,7 @@ fn layout_of_uncached<'tcx>(
         ty::Dynamic(_, _, ty::DynStar) => {
             let mut data = scalar_unit(Int(dl.ptr_sized_integer(), false));
             data.valid_range_mut().start = 0;
-            let mut vtable = scalar_unit(Pointer);
+            let mut vtable = scalar_unit(Pointer(AddressSpace::DATA));
             vtable.valid_range_mut().start = 1;
             tcx.intern_layout(cx.scalar_pair(data, vtable))
         }
index 129213fde7491c8ef02040003c6dc7314af694de..7f109491350f0a21c2bbb5bc3f6b0badd193e4e8 100644 (file)
 use crate::fmt::{self, Debug, Display};
 use crate::marker::{PhantomData, Unsize};
 use crate::mem;
-use crate::ops::{CoerceUnsized, Deref, DerefMut};
+use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn};
 use crate::ptr::{self, NonNull};
 
 mod lazy;
@@ -571,6 +571,16 @@ pub fn take(&self) -> T {
 #[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<T: CoerceUnsized<U>, U> CoerceUnsized<Cell<U>> for Cell<T> {}
 
+// Allow types that wrap `Cell` to also implement `DispatchFromDyn`
+// and become object safe method receivers.
+// Note that currently `Cell` itself cannot be a method receiver
+// because it does not implement Deref.
+// In other words:
+// `self: Cell<&Self>` won't work
+// `self: CellWrapper<Self>` becomes possible
+#[unstable(feature = "dispatch_from_dyn", issue = "none")]
+impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Cell<U>> for Cell<T> {}
+
 impl<T> Cell<[T]> {
     /// Returns a `&[Cell<T>]` from a `&Cell<[T]>`
     ///
@@ -2078,6 +2088,16 @@ fn from(t: T) -> UnsafeCell<T> {
 #[unstable(feature = "coerce_unsized", issue = "18598")]
 impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafeCell<U>> for UnsafeCell<T> {}
 
+// Allow types that wrap `UnsafeCell` to also implement `DispatchFromDyn`
+// and become object safe method receivers.
+// Note that currently `UnsafeCell` itself cannot be a method receiver
+// because it does not implement Deref.
+// In other words:
+// `self: UnsafeCell<&Self>` won't work
+// `self: UnsafeCellWrapper<Self>` becomes possible
+#[unstable(feature = "dispatch_from_dyn", issue = "none")]
+impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafeCell<U>> for UnsafeCell<T> {}
+
 /// [`UnsafeCell`], but [`Sync`].
 ///
 /// This is just an `UnsafeCell`, except it implements `Sync`
@@ -2169,6 +2189,17 @@ fn from(t: T) -> SyncUnsafeCell<T> {
 //#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
 impl<T: CoerceUnsized<U>, U> CoerceUnsized<SyncUnsafeCell<U>> for SyncUnsafeCell<T> {}
 
+// Allow types that wrap `SyncUnsafeCell` to also implement `DispatchFromDyn`
+// and become object safe method receivers.
+// Note that currently `SyncUnsafeCell` itself cannot be a method receiver
+// because it does not implement Deref.
+// In other words:
+// `self: SyncUnsafeCell<&Self>` won't work
+// `self: SyncUnsafeCellWrapper<Self>` becomes possible
+#[unstable(feature = "dispatch_from_dyn", issue = "none")]
+//#[unstable(feature = "sync_unsafe_cell", issue = "95439")]
+impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<SyncUnsafeCell<U>> for SyncUnsafeCell<T> {}
+
 #[allow(unused)]
 fn assert_coerce_unsized(
     a: UnsafeCell<&i32>,
index 0145ba5e3cde63815a4c80a7b76bfc91873fbb0b..c9821bf8109a7f39c43601292327994065131898 100644 (file)
@@ -267,6 +267,7 @@ pub fn new(buf: &'a mut (dyn Write + 'a)) -> Formatter<'a> {
 /// family of functions. It contains a function to format the given value. At
 /// compile time it is ensured that the function and the value have the correct
 /// types, and then this struct is used to canonicalize arguments to one type.
+#[cfg_attr(not(bootstrap), lang = "format_argument")]
 #[derive(Copy, Clone)]
 #[allow(missing_debug_implementations)]
 #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
@@ -279,6 +280,7 @@ pub struct ArgumentV1<'a> {
 /// This struct represents the unsafety of constructing an `Arguments`.
 /// It exists, rather than an unsafe function, in order to simplify the expansion
 /// of `format_args!(..)` and reduce the scope of the `unsafe` block.
+#[cfg_attr(not(bootstrap), lang = "format_unsafe_arg")]
 #[allow(missing_debug_implementations)]
 #[doc(hidden)]
 #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
@@ -473,8 +475,8 @@ pub fn estimated_capacity(&self) -> usize {
 /// ```
 ///
 /// [`format()`]: ../../std/fmt/fn.format.html
+#[cfg_attr(not(bootstrap), lang = "format_arguments")]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(not(test), rustc_diagnostic_item = "Arguments")]
 #[derive(Copy, Clone)]
 pub struct Arguments<'a> {
     // Format string pieces to print.
index 37202b2774dc63d95086c9d7ef6d7fa3f6231742..11a50951a75dad1798ad15167388e895053f1ece 100644 (file)
@@ -5,7 +5,9 @@
 //! these can be statically allocated and are slightly optimized for the runtime
 #![allow(missing_debug_implementations)]
 
+#[cfg_attr(not(bootstrap), lang = "format_placeholder")]
 #[derive(Copy, Clone)]
+// FIXME: Rename this to Placeholder
 pub struct Argument {
     pub position: usize,
     pub format: FormatSpec,
@@ -20,7 +22,22 @@ pub struct FormatSpec {
     pub width: Count,
 }
 
+impl Argument {
+    #[inline(always)]
+    pub const fn new(
+        position: usize,
+        fill: char,
+        align: Alignment,
+        flags: u32,
+        precision: Count,
+        width: Count,
+    ) -> Self {
+        Self { position, format: FormatSpec { fill, align, flags, precision, width } }
+    }
+}
+
 /// Possible alignments that can be requested as part of a formatting directive.
+#[cfg_attr(not(bootstrap), lang = "format_alignment")]
 #[derive(Copy, Clone, PartialEq, Eq)]
 pub enum Alignment {
     /// Indication that contents should be left-aligned.
@@ -34,6 +51,7 @@ pub enum Alignment {
 }
 
 /// Used by [width](https://doc.rust-lang.org/std/fmt/#width) and [precision](https://doc.rust-lang.org/std/fmt/#precision) specifiers.
+#[cfg_attr(not(bootstrap), lang = "format_count")]
 #[derive(Copy, Clone)]
 pub enum Count {
     /// Specified with a literal number, stores the value
index e3157b66902eb9dbfbfafbc505bdb786c88cbb2b..3d7ccffa1735c97f5f54666aad381d06a22b5043 100644 (file)
 //!
 //! #### Statements
 //!  - Assign statements work via normal Rust assignment.
-//!  - [`Retag`] statements have an associated function.
+//!  - [`Retag`], [`StorageLive`], [`StorageDead`], [`Deinit`] 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.
+//!  - [`Discriminant`] and [`Len`] have associated functions.
+//!  - Unary and binary operations use their normal Rust syntax - `a * b`, `!c`, etc.
+//!  - Checked binary operations are represented by wrapping the associated binop in [`Checked`].
+//!  - Array repetition syntax (`[foo; 10]`) creates the associated rvalue.
 //!
 //! #### Terminators
 //!
@@ -261,6 +264,9 @@ pub fn $($sig)* { panic!() }
 define!("mir_call", fn Call<T>(place: T, goto: BasicBlock, call: T));
 define!("mir_storage_live", fn StorageLive<T>(local: T));
 define!("mir_storage_dead", fn StorageDead<T>(local: T));
+define!("mir_deinit", fn Deinit<T>(place: T));
+define!("mir_checked", fn Checked<T>(binop: T) -> (T, bool));
+define!("mir_len", fn Len<T>(place: T) -> usize);
 define!("mir_retag", fn Retag<T>(place: T));
 define!("mir_move", fn Move<T>(place: T) -> T);
 define!("mir_static", fn Static<T>(s: T) -> &'static T);
index 14367eb09bc75e0e00c13ec9a4025638df8630f0..818721062d7f702aeba8df4096d55fbc6456427e 100644 (file)
@@ -1861,7 +1861,8 @@ macro_rules! if_not_8_bit {
     ($_:ident, $($tt:tt)*) => { $($tt)* };
 }
 
-#[cfg(target_has_atomic_load_store = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic_load_store))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic_load_store = "8"))]
 macro_rules! atomic_int {
     ($cfg_cas:meta,
      $cfg_align:meta,
@@ -2988,7 +2989,8 @@ macro_rules! atomic_int_ptr_sized {
 }
 
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 fn strongest_failure_ordering(order: Ordering) -> Ordering {
     match order {
         Release => Relaxed,
@@ -3030,7 +3032,8 @@ unsafe fn atomic_load<T: Copy>(dst: *const T, order: Ordering) -> T {
 }
 
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_swap<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_swap`.
@@ -3047,7 +3050,8 @@ unsafe fn atomic_swap<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// Returns the previous value (like __sync_fetch_and_add).
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_add`.
@@ -3064,7 +3068,8 @@ unsafe fn atomic_add<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// Returns the previous value (like __sync_fetch_and_sub).
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_sub`.
@@ -3080,7 +3085,8 @@ unsafe fn atomic_sub<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 }
 
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_compare_exchange<T: Copy>(
     dst: *mut T,
@@ -3115,7 +3121,8 @@ unsafe fn atomic_compare_exchange<T: Copy>(
 }
 
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_compare_exchange_weak<T: Copy>(
     dst: *mut T,
@@ -3150,7 +3157,8 @@ unsafe fn atomic_compare_exchange_weak<T: Copy>(
 }
 
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_and<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_and`
@@ -3166,7 +3174,8 @@ unsafe fn atomic_and<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 }
 
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_nand<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_nand`
@@ -3182,7 +3191,8 @@ unsafe fn atomic_nand<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 }
 
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_or<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_or`
@@ -3198,7 +3208,8 @@ unsafe fn atomic_or<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 }
 
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_xor<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_xor`
@@ -3215,7 +3226,8 @@ unsafe fn atomic_xor<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// returns the max value (signed comparison)
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_max<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_max`
@@ -3232,7 +3244,8 @@ unsafe fn atomic_max<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// returns the min value (signed comparison)
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_min<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_min`
@@ -3249,7 +3262,8 @@ unsafe fn atomic_min<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// returns the max value (unsigned comparison)
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_umax<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_umax`
@@ -3266,7 +3280,8 @@ unsafe fn atomic_umax<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
 
 /// returns the min value (unsigned comparison)
 #[inline]
-#[cfg(target_has_atomic = "8")]
+#[cfg_attr(not(bootstrap), cfg(target_has_atomic))]
+#[cfg_attr(bootstrap, cfg(target_has_atomic = "8"))]
 #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
 unsafe fn atomic_umin<T: Copy>(dst: *mut T, val: T, order: Ordering) -> T {
     // SAFETY: the caller must uphold the safety contract for `atomic_umin`
index f0e4f5d8a8013d613098c4ecd0a2dfee921ac24a..938935771d64e24c84d775cd2c59472344a02a04 100644 (file)
@@ -74,6 +74,7 @@ pub fn is_available() -> bool {
 ///
 /// This is both the input and output of `#[proc_macro]`, `#[proc_macro_attribute]`
 /// and `#[proc_macro_derive]` definitions.
+#[rustc_diagnostic_item = "TokenStream"]
 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
 #[derive(Clone)]
 pub struct TokenStream(Option<bridge::client::TokenStream>);
@@ -581,7 +582,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 /// A line-column pair representing the start or end of a `Span`.
 #[unstable(feature = "proc_macro_span", issue = "54725")]
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub struct LineColumn {
     /// The 1-indexed line in the source file on which the span starts or ends (inclusive).
     #[unstable(feature = "proc_macro_span", issue = "54725")]
index c1e3e48b04468c8c501d45392b3c06b35fa34ac8..c6bb09b0417f3c918fd06b2b3a377b9829d2f592 100644 (file)
@@ -319,19 +319,10 @@ pub(crate) fn send(
     ) -> Result<(), SendTimeoutError<T>> {
         let token = &mut Token::default();
         loop {
-            // Try sending a message several times.
-            let backoff = Backoff::new();
-            loop {
-                if self.start_send(token) {
-                    let res = unsafe { self.write(token, msg) };
-                    return res.map_err(SendTimeoutError::Disconnected);
-                }
-
-                if backoff.is_completed() {
-                    break;
-                } else {
-                    backoff.spin_light();
-                }
+            // Try sending a message.
+            if self.start_send(token) {
+                let res = unsafe { self.write(token, msg) };
+                return res.map_err(SendTimeoutError::Disconnected);
             }
 
             if let Some(d) = deadline {
@@ -379,6 +370,7 @@ pub(crate) fn try_recv(&self) -> Result<T, TryRecvError> {
     pub(crate) fn recv(&self, deadline: Option<Instant>) -> Result<T, RecvTimeoutError> {
         let token = &mut Token::default();
         loop {
+            // Try receiving a message.
             if self.start_recv(token) {
                 let res = unsafe { self.read(token) };
                 return res.map_err(|_| RecvTimeoutError::Disconnected);
index cfe42750d5239a6a46ab629027581df795c12129..d053d69e26eeeb819c9da040bf8141870fc914b1 100644 (file)
@@ -105,10 +105,8 @@ pub fn new() -> Self {
 
     /// Backs off using lightweight spinning.
     ///
-    /// This method should be used for:
-    ///     - Retrying an operation because another thread made progress. i.e. on CAS failure.
-    ///     - Waiting for an operation to complete by spinning optimistically for a few iterations
-    ///     before falling back to parking the thread (see `Backoff::is_completed`).
+    /// This method should be used for retrying an operation because another thread made
+    /// progress. i.e. on CAS failure.
     #[inline]
     pub fn spin_light(&self) {
         let step = self.step.get().min(SPIN_LIMIT);
@@ -134,10 +132,4 @@ pub fn spin_heavy(&self) {
 
         self.step.set(self.step.get() + 1);
     }
-
-    /// Returns `true` if quadratic backoff has completed and parking the thread is advised.
-    #[inline]
-    pub fn is_completed(&self) -> bool {
-        self.step.get() > SPIN_LIMIT
-    }
 }
index c31fb3a48dabb474bda286a79d59a9fcfe9cc119..236d2f2ee29280cac96ce34c512c7bae291a0786 100644 (file)
 // Note, however, that we run on lots older linuxes, as well as cross
 // compiling from a newer linux to an older linux, so we also have a
 // fallback implementation to use as well.
-#[cfg(any(
-    target_os = "linux",
-    target_os = "fuchsia",
-    target_os = "redox",
-    target_os = "emscripten"
-))]
-#[cfg_attr(target_family = "wasm", allow(unused))] // might remain unused depending on target details (e.g. wasm32-unknown-emscripten)
+#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "redox"))]
 pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
     use crate::mem;
     use crate::sys_common::thread_local_dtor::register_dtor_fallback;
@@ -89,7 +83,8 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
     }
 }
 
-#[cfg(any(target_os = "vxworks", target_os = "horizon"))]
+#[cfg(any(target_os = "vxworks", target_os = "horizon", target_os = "emscripten"))]
+#[cfg_attr(target_family = "wasm", allow(unused))] // might remain unused depending on target details (e.g. wasm32-unknown-emscripten)
 pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
     use crate::sys_common::thread_local_dtor::register_dtor_fallback;
     register_dtor_fallback(t, dtor);
index 1a2c125566139d11370637b368d3d954314586ff..bf3c81fcc980b95968583fe33b0ccdaebe0a3b48 100644 (file)
@@ -120,16 +120,13 @@ fn x86_all() {
     println!("avx512dq: {:?}", is_x86_feature_detected!("avx512dq"));
     println!("avx512er: {:?}", is_x86_feature_detected!("avx512er"));
     println!("avx512f: {:?}", is_x86_feature_detected!("avx512f"));
-    println!("avx512gfni: {:?}", is_x86_feature_detected!("avx512gfni"));
     println!("avx512ifma: {:?}", is_x86_feature_detected!("avx512ifma"));
     println!("avx512pf: {:?}", is_x86_feature_detected!("avx512pf"));
-    println!("avx512vaes: {:?}", is_x86_feature_detected!("avx512vaes"));
     println!("avx512vbmi2: {:?}", is_x86_feature_detected!("avx512vbmi2"));
     println!("avx512vbmi: {:?}", is_x86_feature_detected!("avx512vbmi"));
     println!("avx512vl: {:?}", is_x86_feature_detected!("avx512vl"));
     println!("avx512vnni: {:?}", is_x86_feature_detected!("avx512vnni"));
     println!("avx512vp2intersect: {:?}", is_x86_feature_detected!("avx512vp2intersect"));
-    println!("avx512vpclmulqdq: {:?}", is_x86_feature_detected!("avx512vpclmulqdq"));
     println!("avx512vpopcntdq: {:?}", is_x86_feature_detected!("avx512vpopcntdq"));
     println!("avx: {:?}", is_x86_feature_detected!("avx"));
     println!("bmi1: {:?}", is_x86_feature_detected!("bmi1"));
@@ -138,6 +135,7 @@ fn x86_all() {
     println!("f16c: {:?}", is_x86_feature_detected!("f16c"));
     println!("fma: {:?}", is_x86_feature_detected!("fma"));
     println!("fxsr: {:?}", is_x86_feature_detected!("fxsr"));
+    println!("gfni: {:?}", is_x86_feature_detected!("gfni"));
     println!("lzcnt: {:?}", is_x86_feature_detected!("lzcnt"));
     //println!("movbe: {:?}", is_x86_feature_detected!("movbe")); // movbe is unsupported as a target feature
     println!("pclmulqdq: {:?}", is_x86_feature_detected!("pclmulqdq"));
@@ -154,6 +152,8 @@ fn x86_all() {
     println!("sse: {:?}", is_x86_feature_detected!("sse"));
     println!("ssse3: {:?}", is_x86_feature_detected!("ssse3"));
     println!("tbm: {:?}", is_x86_feature_detected!("tbm"));
+    println!("vaes: {:?}", is_x86_feature_detected!("vaes"));
+    println!("vpclmulqdq: {:?}", is_x86_feature_detected!("vpclmulqdq"));
     println!("xsave: {:?}", is_x86_feature_detected!("xsave"));
     println!("xsavec: {:?}", is_x86_feature_detected!("xsavec"));
     println!("xsaveopt: {:?}", is_x86_feature_detected!("xsaveopt"));
index 790411f93c4b5eada3c23abb4c9a063fb0b24d99..a0c30f3e3c75adcd6ee7efc94014ebcead61c507 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 790411f93c4b5eada3c23abb4c9a063fb0b24d99
+Subproject commit a0c30f3e3c75adcd6ee7efc94014ebcead61c507
index be69f819c6428f8e88332ab7889656ec7482a88a..3856bb64fb310331f44899dcd940708335e4e24c 100644 (file)
@@ -16,12 +16,17 @@ fn main() {
     let mut build_lock;
     let _build_lock_guard;
     if cfg!(any(unix, windows)) {
-        build_lock = fd_lock::RwLock::new(t!(std::fs::File::create(config.out.join("lock"))));
+        let path = config.out.join("lock");
+        build_lock = fd_lock::RwLock::new(t!(std::fs::File::create(&path)));
         _build_lock_guard = match build_lock.try_write() {
             Ok(lock) => lock,
             err => {
-                println!("warning: build directory locked, waiting for lock");
                 drop(err);
+                if let Some(pid) = get_lock_owner(&path) {
+                    println!("warning: build directory locked by process {pid}, waiting for lock");
+                } else {
+                    println!("warning: build directory locked, waiting for lock");
+                }
                 t!(build_lock.write())
             }
         };
@@ -98,3 +103,30 @@ fn check_version(config: &Config) -> Option<String> {
 
     Some(msg)
 }
+
+/// Get the PID of the process which took the write lock by
+/// parsing `/proc/locks`.
+#[cfg(target_os = "linux")]
+fn get_lock_owner(f: &std::path::Path) -> Option<u64> {
+    use std::fs::File;
+    use std::io::{BufRead, BufReader};
+    use std::os::unix::fs::MetadataExt;
+
+    let lock_inode = std::fs::metadata(f).ok()?.ino();
+    let lockfile = File::open("/proc/locks").ok()?;
+    BufReader::new(lockfile).lines().find_map(|line| {
+        //                       pid--vvvvvv       vvvvvvv--- inode
+        // 21: FLOCK  ADVISORY  WRITE 359238 08:02:3719774 0 EOF
+        let line = line.ok()?;
+        let parts = line.split_whitespace().collect::<Vec<_>>();
+        let (pid, inode) = (parts[4].parse::<u64>().ok()?, &parts[5]);
+        let inode = inode.rsplit_once(':')?.1.parse::<u64>().ok()?;
+        if inode == lock_inode { Some(pid) } else { None }
+    })
+}
+
+#[cfg(not(target_os = "linux"))]
+fn get_lock_owner(_: &std::path::Path) -> Option<u64> {
+    // FIXME: Implement on other OS's
+    None
+}
index b41d60d51a8b5972f75ea63e518d68e461f7df0e..fdd659c60ca7f51181fc0280a1b5309a0207ad03 100644 (file)
@@ -965,6 +965,9 @@ fn parse_inner<'a>(args: &[String], get_toml: impl 'a + Fn(&Path) -> TomlConfig)
         config.changelog_seen = toml.changelog_seen;
 
         let build = toml.build.unwrap_or_default();
+        if let Some(file_build) = build.build {
+            config.build = TargetSelection::from_user(&file_build);
+        };
 
         set(&mut config.out, flags.build_dir.or_else(|| build.build_dir.map(PathBuf::from)));
         // NOTE: Bootstrap spawns various commands with different working directories.
index c30c9131745c81e2f41cf8277852685ac1df579c..681ecbfeb5b8fca058a53948d10bee17ab8d8bd7 100644 (file)
@@ -19,6 +19,13 @@ fn download_ci_llvm() {
     assert_eq!(parse_llvm(""), if_available);
     assert_eq!(parse_llvm("rust.channel = \"dev\""), if_available);
     assert!(!parse_llvm("rust.channel = \"stable\""));
+    assert!(parse_llvm("build.build = \"x86_64-unknown-linux-gnu\""));
+    assert!(parse_llvm(
+        "llvm.assertions = true \r\n build.build = \"x86_64-unknown-linux-gnu\" \r\n llvm.download-ci-llvm = \"if-available\""
+    ));
+    assert!(!parse_llvm(
+        "llvm.assertions = true \r\n build.build = \"aarch64-apple-darwin\" \r\n llvm.download-ci-llvm = \"if-available\""
+    ));
 }
 
 // FIXME: add test for detecting `src` and `out`
index cb5706ca0a6516f838cc56581d580bfdf34207f8..3acc2d4b5c4b1093a2ab204c1e3b2861d3e864bf 100644 (file)
@@ -180,43 +180,40 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool {
     // https://doc.rust-lang.org/rustc/platform-support.html#tier-1
     let supported_platforms = [
         // tier 1
-        "aarch64-unknown-linux-gnu",
-        "i686-pc-windows-gnu",
-        "i686-pc-windows-msvc",
-        "i686-unknown-linux-gnu",
-        "x86_64-unknown-linux-gnu",
-        "x86_64-apple-darwin",
-        "x86_64-pc-windows-gnu",
-        "x86_64-pc-windows-msvc",
+        ("aarch64-unknown-linux-gnu", false),
+        ("i686-pc-windows-gnu", false),
+        ("i686-pc-windows-msvc", false),
+        ("i686-unknown-linux-gnu", false),
+        ("x86_64-unknown-linux-gnu", true),
+        ("x86_64-apple-darwin", true),
+        ("x86_64-pc-windows-gnu", true),
+        ("x86_64-pc-windows-msvc", true),
         // tier 2 with host tools
-        "aarch64-apple-darwin",
-        "aarch64-pc-windows-msvc",
-        "aarch64-unknown-linux-musl",
-        "arm-unknown-linux-gnueabi",
-        "arm-unknown-linux-gnueabihf",
-        "armv7-unknown-linux-gnueabihf",
-        "mips-unknown-linux-gnu",
-        "mips64-unknown-linux-gnuabi64",
-        "mips64el-unknown-linux-gnuabi64",
-        "mipsel-unknown-linux-gnu",
-        "powerpc-unknown-linux-gnu",
-        "powerpc64-unknown-linux-gnu",
-        "powerpc64le-unknown-linux-gnu",
-        "riscv64gc-unknown-linux-gnu",
-        "s390x-unknown-linux-gnu",
-        "x86_64-unknown-freebsd",
-        "x86_64-unknown-illumos",
-        "x86_64-unknown-linux-musl",
-        "x86_64-unknown-netbsd",
+        ("aarch64-apple-darwin", false),
+        ("aarch64-pc-windows-msvc", false),
+        ("aarch64-unknown-linux-musl", false),
+        ("arm-unknown-linux-gnueabi", false),
+        ("arm-unknown-linux-gnueabihf", false),
+        ("armv7-unknown-linux-gnueabihf", false),
+        ("mips-unknown-linux-gnu", false),
+        ("mips64-unknown-linux-gnuabi64", false),
+        ("mips64el-unknown-linux-gnuabi64", false),
+        ("mipsel-unknown-linux-gnu", false),
+        ("powerpc-unknown-linux-gnu", false),
+        ("powerpc64-unknown-linux-gnu", false),
+        ("powerpc64le-unknown-linux-gnu", false),
+        ("riscv64gc-unknown-linux-gnu", false),
+        ("s390x-unknown-linux-gnu", false),
+        ("x86_64-unknown-freebsd", false),
+        ("x86_64-unknown-illumos", false),
+        ("x86_64-unknown-linux-musl", false),
+        ("x86_64-unknown-netbsd", false),
     ];
-    if !supported_platforms.contains(&&*config.build.triple) {
-        return false;
-    }
 
-    let triple = &*config.build.triple;
-    if (triple == "aarch64-unknown-linux-gnu" || triple.contains("i686")) && asserts {
-        // No alt builder for aarch64-unknown-linux-gnu today.
-        return false;
+    if !supported_platforms.contains(&(&*config.build.triple, asserts)) {
+        if asserts == true || !supported_platforms.contains(&(&*config.build.triple, true)) {
+            return false;
+        }
     }
 
     if CiEnv::is_ci() {
index 34a7068e5da53b84b75f5e5147027801a2fd9d36..3cb6ad10e72b8e43cad38a6cb60e2427f6fa03b4 100644 (file)
@@ -15,7 +15,7 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, IndexEntry};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId, LOCAL_CRATE};
 use rustc_hir::PredicateOrigin;
 use rustc_hir_analysis::hir_ty_to_ty;
 use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData};
@@ -116,7 +116,8 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<
         }
     });
 
-    Item::from_hir_id_and_parts(doc.id, Some(doc.name), ModuleItem(Module { items, span }), cx)
+    let kind = ModuleItem(Module { items, span });
+    Item::from_def_id_and_parts(doc.def_id.to_def_id(), Some(doc.name), kind, cx)
 }
 
 fn clean_generic_bound<'tcx>(
@@ -2067,12 +2068,12 @@ struct OneLevelVisitor<'hir> {
     map: rustc_middle::hir::map::Map<'hir>,
     item: Option<&'hir hir::Item<'hir>>,
     looking_for: Ident,
-    target_hir_id: hir::HirId,
+    target_def_id: LocalDefId,
 }
 
 impl<'hir> OneLevelVisitor<'hir> {
-    fn new(map: rustc_middle::hir::map::Map<'hir>, target_hir_id: hir::HirId) -> Self {
-        Self { map, item: None, looking_for: Ident::empty(), target_hir_id }
+    fn new(map: rustc_middle::hir::map::Map<'hir>, target_def_id: LocalDefId) -> Self {
+        Self { map, item: None, looking_for: Ident::empty(), target_def_id }
     }
 
     fn reset(&mut self, looking_for: Ident) {
@@ -2092,7 +2093,7 @@ fn visit_item(&mut self, item: &'hir hir::Item<'hir>) {
         if self.item.is_none()
             && item.ident == self.looking_for
             && matches!(item.kind, hir::ItemKind::Use(_, _))
-            || item.hir_id() == self.target_hir_id
+            || item.owner_id.def_id == self.target_def_id
         {
             self.item = Some(item);
         }
@@ -2106,11 +2107,11 @@ fn visit_item(&mut self, item: &'hir hir::Item<'hir>) {
 fn get_all_import_attributes<'hir>(
     mut item: &hir::Item<'hir>,
     tcx: TyCtxt<'hir>,
-    target_hir_id: hir::HirId,
+    target_def_id: LocalDefId,
     attributes: &mut Vec<ast::Attribute>,
 ) {
     let hir_map = tcx.hir();
-    let mut visitor = OneLevelVisitor::new(hir_map, target_hir_id);
+    let mut visitor = OneLevelVisitor::new(hir_map, target_def_id);
     // If the item is an import and has at least a path with two parts, we go into it.
     while let hir::ItemKind::Use(path, _) = item.kind &&
         path.segments.len() > 1 &&
@@ -2138,7 +2139,7 @@ fn clean_maybe_renamed_item<'tcx>(
     cx: &mut DocContext<'tcx>,
     item: &hir::Item<'tcx>,
     renamed: Option<Symbol>,
-    import_id: Option<hir::HirId>,
+    import_id: Option<LocalDefId>,
 ) -> Vec<Item> {
     use hir::ItemKind;
 
@@ -2183,7 +2184,7 @@ fn clean_maybe_renamed_item<'tcx>(
                 generics: clean_generics(generics, cx),
                 fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
             }),
-            ItemKind::Impl(impl_) => return clean_impl(impl_, item.hir_id(), cx),
+            ItemKind::Impl(impl_) => return clean_impl(impl_, item.owner_id.def_id, cx),
             // proc macros can have a name set by attributes
             ItemKind::Fn(ref sig, generics, body_id) => {
                 clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
@@ -2218,10 +2219,10 @@ fn clean_maybe_renamed_item<'tcx>(
 
         let mut extra_attrs = Vec::new();
         if let Some(hir::Node::Item(use_node)) =
-            import_id.and_then(|hir_id| cx.tcx.hir().find(hir_id))
+            import_id.and_then(|def_id| cx.tcx.hir().find_by_def_id(def_id))
         {
             // We get all the various imports' attributes.
-            get_all_import_attributes(use_node, cx.tcx, item.hir_id(), &mut extra_attrs);
+            get_all_import_attributes(use_node, cx.tcx, item.owner_id.def_id, &mut extra_attrs);
         }
 
         if !extra_attrs.is_empty() {
@@ -2244,12 +2245,12 @@ fn clean_maybe_renamed_item<'tcx>(
 
 fn clean_variant<'tcx>(variant: &hir::Variant<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
     let kind = VariantItem(clean_variant_data(&variant.data, &variant.disr_expr, cx));
-    Item::from_hir_id_and_parts(variant.hir_id, Some(variant.ident.name), kind, cx)
+    Item::from_def_id_and_parts(variant.def_id.to_def_id(), Some(variant.ident.name), kind, cx)
 }
 
 fn clean_impl<'tcx>(
     impl_: &hir::Impl<'tcx>,
-    hir_id: hir::HirId,
+    def_id: LocalDefId,
     cx: &mut DocContext<'tcx>,
 ) -> Vec<Item> {
     let tcx = cx.tcx;
@@ -2260,7 +2261,6 @@ fn clean_impl<'tcx>(
         .iter()
         .map(|ii| clean_impl_item(tcx.hir().impl_item(ii.id), cx))
         .collect::<Vec<_>>();
-    let def_id = tcx.hir().local_def_id(hir_id);
 
     // If this impl block is an implementation of the Deref trait, then we
     // need to try inlining the target's inherent impl blocks as well.
@@ -2289,7 +2289,7 @@ fn clean_impl<'tcx>(
                 ImplKind::Normal
             },
         }));
-        Item::from_hir_id_and_parts(hir_id, None, kind, cx)
+        Item::from_def_id_and_parts(def_id.to_def_id(), None, kind, cx)
     };
     if let Some(type_alias) = type_alias {
         ret.push(make_item(trait_.clone(), type_alias, items.clone()));
@@ -2510,8 +2510,8 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
             hir::ForeignItemKind::Type => ForeignTypeItem,
         };
 
-        Item::from_hir_id_and_parts(
-            item.hir_id(),
+        Item::from_def_id_and_parts(
+            item.owner_id.def_id.to_def_id(),
             Some(renamed.unwrap_or(item.ident.name)),
             kind,
             cx,
index a020ccd53b8422b55cc80ef0a930856572cdbc1a..3b258c4d919f84e385c841bdcec428fd8ba0a9ec 100644 (file)
@@ -439,17 +439,6 @@ pub(crate) fn doc_value(&self) -> Option<String> {
         self.attrs.doc_value()
     }
 
-    /// Convenience wrapper around [`Self::from_def_id_and_parts`] which converts
-    /// `hir_id` to a [`DefId`]
-    pub(crate) fn from_hir_id_and_parts(
-        hir_id: hir::HirId,
-        name: Option<Symbol>,
-        kind: ItemKind,
-        cx: &mut DocContext<'_>,
-    ) -> Item {
-        Item::from_def_id_and_parts(cx.tcx.hir().local_def_id(hir_id).to_def_id(), name, kind, cx)
-    }
-
     pub(crate) fn from_def_id_and_parts(
         def_id: DefId,
         name: Option<Symbol>,
@@ -2416,10 +2405,7 @@ pub(crate) fn value(&self, tcx: TyCtxt<'_>) -> Option<String> {
 
     pub(crate) fn is_literal(&self, tcx: TyCtxt<'_>) -> bool {
         match *self {
-            ConstantKind::TyConst { .. } => false,
-            ConstantKind::Extern { def_id } => def_id.as_local().map_or(false, |def_id| {
-                is_literal_expr(tcx, tcx.hir().local_def_id_to_hir_id(def_id))
-            }),
+            ConstantKind::TyConst { .. } | ConstantKind::Extern { .. } => false,
             ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
                 is_literal_expr(tcx, body.hir_id)
             }
index a12f764fa8e3b739404df7937b83969a10e6bb8f..ca3a70c7236feb2a617527c19712bb65b81882c5 100644 (file)
 pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
     let module = crate::visit_ast::RustdocVisitor::new(cx).visit();
 
-    for &cnum in cx.tcx.crates(()) {
-        // Analyze doc-reachability for extern items
-        crate::visit_lib::lib_embargo_visit_item(cx, cnum.as_def_id());
-    }
-
     // Clean the crate, translating the entire librustc_ast AST to one that is
     // understood by rustdoc.
     let mut module = clean_doc_module(&module, cx);
index 10b606f425ea41fcd4839ff72fd0d95806428d04..0ce43f7db8e8b0d9d8fb5cd768141da3a27cd023 100644 (file)
@@ -41,6 +41,7 @@ pub(crate) struct ResolverCaches {
     pub(crate) traits_in_scope: DefIdMap<Vec<TraitCandidate>>,
     pub(crate) all_trait_impls: Option<Vec<DefId>>,
     pub(crate) all_macro_rules: FxHashMap<Symbol, Res<NodeId>>,
+    pub(crate) extern_doc_reachable: DefIdSet,
 }
 
 pub(crate) struct DocContext<'tcx> {
@@ -363,6 +364,10 @@ pub(crate) fn run_global_ctxt(
         show_coverage,
     };
 
+    ctxt.cache
+        .effective_visibilities
+        .init(mem::take(&mut ctxt.resolver_caches.extern_doc_reachable));
+
     // Small hack to force the Sized trait to be present.
     //
     // Note that in case of `#![no_core]`, the trait is not available.
index c1a652c75f4a16a0999fface3e8d8f8db60752af..37a1005cba1fc82a97ef7690805aac5a121c5a3b 100644 (file)
@@ -2,10 +2,8 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{ColorConfig, ErrorGuaranteed, FatalError};
-use rustc_hir as hir;
-use rustc_hir::def_id::LOCAL_CRATE;
-use rustc_hir::intravisit;
-use rustc_hir::{HirId, CRATE_HIR_ID};
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::{self as hir, intravisit, CRATE_HIR_ID};
 use rustc_interface::interface;
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
@@ -140,7 +138,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
                     };
                     hir_collector.visit_testable(
                         "".to_string(),
-                        CRATE_HIR_ID,
+                        CRATE_DEF_ID,
                         tcx.hir().span(CRATE_HIR_ID),
                         |this| tcx.hir().walk_toplevel_module(this),
                     );
@@ -1214,11 +1212,11 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> {
     fn visit_testable<F: FnOnce(&mut Self)>(
         &mut self,
         name: String,
-        hir_id: HirId,
+        def_id: LocalDefId,
         sp: Span,
         nested: F,
     ) {
-        let ast_attrs = self.tcx.hir().attrs(hir_id);
+        let ast_attrs = self.tcx.hir().attrs(self.tcx.hir().local_def_id_to_hir_id(def_id));
         if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) {
             if !cfg.matches(&self.sess.parse_sess, Some(self.tcx.features())) {
                 return;
@@ -1247,7 +1245,7 @@ fn visit_testable<F: FnOnce(&mut Self)>(
                 self.collector.enable_per_target_ignores,
                 Some(&crate::html::markdown::ExtraInfo::new(
                     self.tcx,
-                    hir_id,
+                    def_id.to_def_id(),
                     span_of_attrs(&attrs).unwrap_or(sp),
                 )),
             );
@@ -1276,37 +1274,37 @@ fn visit_item(&mut self, item: &'hir hir::Item<'_>) {
             _ => item.ident.to_string(),
         };
 
-        self.visit_testable(name, item.hir_id(), item.span, |this| {
+        self.visit_testable(name, item.owner_id.def_id, item.span, |this| {
             intravisit::walk_item(this, item);
         });
     }
 
     fn visit_trait_item(&mut self, item: &'hir hir::TraitItem<'_>) {
-        self.visit_testable(item.ident.to_string(), item.hir_id(), item.span, |this| {
+        self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| {
             intravisit::walk_trait_item(this, item);
         });
     }
 
     fn visit_impl_item(&mut self, item: &'hir hir::ImplItem<'_>) {
-        self.visit_testable(item.ident.to_string(), item.hir_id(), item.span, |this| {
+        self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| {
             intravisit::walk_impl_item(this, item);
         });
     }
 
     fn visit_foreign_item(&mut self, item: &'hir hir::ForeignItem<'_>) {
-        self.visit_testable(item.ident.to_string(), item.hir_id(), item.span, |this| {
+        self.visit_testable(item.ident.to_string(), item.owner_id.def_id, item.span, |this| {
             intravisit::walk_foreign_item(this, item);
         });
     }
 
     fn visit_variant(&mut self, v: &'hir hir::Variant<'_>) {
-        self.visit_testable(v.ident.to_string(), v.hir_id, v.span, |this| {
+        self.visit_testable(v.ident.to_string(), v.def_id, v.span, |this| {
             intravisit::walk_variant(this, v);
         });
     }
 
     fn visit_field_def(&mut self, f: &'hir hir::FieldDef<'_>) {
-        self.visit_testable(f.ident.to_string(), f.hir_id, f.span, |this| {
+        self.visit_testable(f.ident.to_string(), f.def_id, f.span, |this| {
             intravisit::walk_field_def(this, f);
         });
     }
index 4ff67fe1551dd019f638bc79ce4ee6460047e6bf..d7739b8534f309e29eec30e308c77ee97b0702b6 100644 (file)
@@ -27,7 +27,6 @@
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::DefId;
-use rustc_hir::HirId;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::edition::Edition;
 use rustc_span::{Span, Symbol};
@@ -296,7 +295,9 @@ fn next(&mut self) -> Option<Self::Item> {
             let channel = if test.contains("#![feature(") { "&amp;version=nightly" } else { "" };
 
             // These characters don't need to be escaped in a URI.
-            // FIXME: use a library function for percent encoding.
+            // See https://url.spec.whatwg.org/#query-percent-encode-set
+            // and https://url.spec.whatwg.org/#urlencoded-parsing
+            // and https://url.spec.whatwg.org/#url-code-points
             fn dont_escape(c: u8) -> bool {
                 (b'a' <= c && c <= b'z')
                     || (b'A' <= c && c <= b'Z')
@@ -304,17 +305,32 @@ fn dont_escape(c: u8) -> bool {
                     || c == b'-'
                     || c == b'_'
                     || c == b'.'
+                    || c == b','
                     || c == b'~'
                     || c == b'!'
                     || c == b'\''
                     || c == b'('
                     || c == b')'
                     || c == b'*'
+                    || c == b'/'
+                    || c == b';'
+                    || c == b':'
+                    || c == b'?'
+                    // As described in urlencoded-parsing, the
+                    // first `=` is the one that separates key from
+                    // value. Following `=`s are part of the value.
+                    || c == b'='
             }
             let mut test_escaped = String::new();
             for b in test.bytes() {
                 if dont_escape(b) {
                     test_escaped.push(char::from(b));
+                } else if b == b' ' {
+                    // URL queries are decoded with + replaced with SP
+                    test_escaped.push('+');
+                } else if b == b'%' {
+                    test_escaped.push('%');
+                    test_escaped.push('%');
                 } else {
                     write!(test_escaped, "%{:02X}", b).unwrap();
                 }
@@ -784,45 +800,26 @@ pub(crate) fn find_testable_code<T: doctest::Tester>(
 }
 
 pub(crate) struct ExtraInfo<'tcx> {
-    id: ExtraInfoId,
+    def_id: DefId,
     sp: Span,
     tcx: TyCtxt<'tcx>,
 }
 
-enum ExtraInfoId {
-    Hir(HirId),
-    Def(DefId),
-}
-
 impl<'tcx> ExtraInfo<'tcx> {
-    pub(crate) fn new(tcx: TyCtxt<'tcx>, hir_id: HirId, sp: Span) -> ExtraInfo<'tcx> {
-        ExtraInfo { id: ExtraInfoId::Hir(hir_id), sp, tcx }
-    }
-
-    pub(crate) fn new_did(tcx: TyCtxt<'tcx>, did: DefId, sp: Span) -> ExtraInfo<'tcx> {
-        ExtraInfo { id: ExtraInfoId::Def(did), sp, tcx }
+    pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: DefId, sp: Span) -> ExtraInfo<'tcx> {
+        ExtraInfo { def_id, sp, tcx }
     }
 
     fn error_invalid_codeblock_attr(&self, msg: &str, help: &str) {
-        let hir_id = match self.id {
-            ExtraInfoId::Hir(hir_id) => hir_id,
-            ExtraInfoId::Def(item_did) => {
-                match item_did.as_local() {
-                    Some(item_did) => self.tcx.hir().local_def_id_to_hir_id(item_did),
-                    None => {
-                        // If non-local, no need to check anything.
-                        return;
-                    }
-                }
-            }
-        };
-        self.tcx.struct_span_lint_hir(
-            crate::lint::INVALID_CODEBLOCK_ATTRIBUTES,
-            hir_id,
-            self.sp,
-            msg,
-            |lint| lint.help(help),
-        );
+        if let Some(def_id) = self.def_id.as_local() {
+            self.tcx.struct_span_lint_hir(
+                crate::lint::INVALID_CODEBLOCK_ATTRIBUTES,
+                self.tcx.hir().local_def_id_to_hir_id(def_id),
+                self.sp,
+                msg,
+                |lint| lint.help(help),
+            );
+        }
     }
 }
 
index f824c9e3ad2bd5eacbeec79587c137bb728067a9..508b2bab0eb643e4d1592f731ac59aff7b4295fe 100644 (file)
@@ -391,7 +391,7 @@ fn cmp(
                 };
                 write!(
                     w,
-                    "<div class=\"item-left {stab}{add}import-item\"{id}>\
+                    "<div class=\"item-left{add}{stab}\"{id}>\
                          <code>{vis}{imp}</code>\
                      </div>\
                      {stab_tags_before}{stab_tags}{stab_tags_after}",
@@ -437,7 +437,7 @@ fn cmp(
                 };
                 write!(
                     w,
-                    "<div class=\"item-left {stab}{add}module-item\">\
+                    "<div class=\"item-left{add}{stab}\">\
                         <a class=\"{class}\" href=\"{href}\" title=\"{title}\">{name}</a>\
                         {visibility_emoji}\
                         {unsafety_flag}\
@@ -452,7 +452,7 @@ fn cmp(
                     stab = stab.unwrap_or_default(),
                     unsafety_flag = unsafety_flag,
                     href = item_path(myitem.type_(), myitem.name.unwrap().as_str()),
-                    title = [full_path(cx, myitem), myitem.type_().to_string()]
+                    title = [myitem.type_().to_string(), full_path(cx, myitem)]
                         .iter()
                         .filter_map(|s| if !s.is_empty() { Some(s.as_str()) } else { None })
                         .collect::<Vec<_>>()
index bf83ff2044e696385679555cf00eb38dcd10bb8f..8699508e43916af754f142937b60ac7312714c8b 100644 (file)
@@ -977,8 +977,7 @@ so that we can apply CSS-filters to change the arrow color in themes */
                0 -1px 0 black;
 }
 
-.module-item.unstable,
-.import-item.unstable {
+.item-left.unstable {
        opacity: 0.65;
 }
 
index 86454e1f2eb7316d239d4544c3adeec49e917e89..a689b502f0fccb1d3fe8fd81059c9dcecba64b90 100644 (file)
@@ -815,7 +815,7 @@ fn main_args(at_args: &[String]) -> MainResult {
                 sess.fatal("Compilation failed, aborting rustdoc");
             }
 
-            let global_ctxt = abort_on_err(queries.global_ctxt(), sess);
+            let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess);
 
             global_ctxt.enter(|tcx| {
                 let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || {
index 02b22789608691fed717a4f8cfc59a37a79a0a22..0b22f943dab99db214553c2696f25beeacc8b0c0 100644 (file)
@@ -216,13 +216,7 @@ fn visit_item(&mut self, i: &clean::Item) {
                 );
 
                 let has_doc_example = tests.found_tests != 0;
-                // The `expect_def_id()` should be okay because `local_def_id_to_hir_id`
-                // would presumably panic if a fake `DefIndex` were passed.
-                let hir_id = self
-                    .ctx
-                    .tcx
-                    .hir()
-                    .local_def_id_to_hir_id(i.item_id.expect_def_id().expect_local());
+                let hir_id = DocContext::as_local_hir_id(self.ctx.tcx, i.item_id).unwrap();
                 let (level, source) = self.ctx.tcx.lint_level_at_node(MISSING_DOCS, hir_id);
 
                 // In case we have:
index 6aa2dda980cf31a14a41f014c76805a3c7692eeb..f3961d5017ef4b99c80b7831446733a60c0c1648 100644 (file)
@@ -14,8 +14,8 @@
 use crate::visit_ast::inherits_doc_hidden;
 use rustc_hir as hir;
 use rustc_middle::lint::LintLevelSource;
+use rustc_middle::ty::DefIdTree;
 use rustc_session::lint;
-use rustc_span::symbol::sym;
 
 pub(crate) const CHECK_DOC_TEST_VISIBILITY: Pass = Pass {
     name: "check_doc_test_visibility",
@@ -79,11 +79,11 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -
 
     // The `expect_def_id()` should be okay because `local_def_id_to_hir_id`
     // would presumably panic if a fake `DefIndex` were passed.
-    let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.item_id.expect_def_id().expect_local());
+    let def_id = item.item_id.expect_def_id().expect_local();
 
     // check if parent is trait impl
-    if let Some(parent_hir_id) = cx.tcx.hir().opt_parent_id(hir_id) {
-        if let Some(parent_node) = cx.tcx.hir().find(parent_hir_id) {
+    if let Some(parent_def_id) = cx.tcx.opt_local_parent(def_id) {
+        if let Some(parent_node) = cx.tcx.hir().find_by_def_id(parent_def_id) {
             if matches!(
                 parent_node,
                 hir::Node::Item(hir::Item {
@@ -96,13 +96,16 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -
         }
     }
 
-    if cx.tcx.hir().attrs(hir_id).lists(sym::doc).has_word(sym::hidden)
-        || inherits_doc_hidden(cx.tcx, hir_id)
-        || cx.tcx.hir().span(hir_id).in_derive_expansion()
+    if cx.tcx.is_doc_hidden(def_id.to_def_id())
+        || inherits_doc_hidden(cx.tcx, def_id)
+        || cx.tcx.def_span(def_id.to_def_id()).in_derive_expansion()
     {
         return false;
     }
-    let (level, source) = cx.tcx.lint_level_at_node(crate::lint::MISSING_DOC_CODE_EXAMPLES, hir_id);
+    let (level, source) = cx.tcx.lint_level_at_node(
+        crate::lint::MISSING_DOC_CODE_EXAMPLES,
+        cx.tcx.hir().local_def_id_to_hir_id(def_id),
+    );
     level != lint::Level::Allow || matches!(source, LintLevelSource::Default)
 }
 
index 075951312a6393d738fab17772a2778f9b2085b9..e42921c080945f4b6c6a9df05d02ca0d76e409a8 100644 (file)
@@ -1194,14 +1194,9 @@ fn verify_disambiguator(
             }
 
         // item can be non-local e.g. when using #[doc(primitive = "pointer")]
-        if let Some((src_id, dst_id)) = id
-            .as_local()
-            // The `expect_def_id()` should be okay because `local_def_id_to_hir_id`
-            // would presumably panic if a fake `DefIndex` were passed.
-            .and_then(|dst_id| {
-                item.item_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id))
-            })
-        {
+        if let Some((src_id, dst_id)) = id.as_local().and_then(|dst_id| {
+            item.item_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id))
+        }) {
             if self.cx.tcx.effective_visibilities(()).is_exported(src_id)
                 && !self.cx.tcx.effective_visibilities(()).is_exported(dst_id)
             {
index 42677bd8497483cce642162000a7ffc4848b07e8..f690c49005d9c70e455805f791d2d6bef49757aa 100644 (file)
@@ -2,6 +2,7 @@
 use crate::core::ResolverCaches;
 use crate::passes::collect_intra_doc_links::preprocessed_markdown_links;
 use crate::passes::collect_intra_doc_links::{Disambiguator, PreprocessedMarkdownLink};
+use crate::visit_lib::early_lib_embargo_visit_item;
 
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
 use rustc_ast::{self as ast, ItemKind};
@@ -34,6 +35,8 @@ pub(crate) fn early_resolve_intra_doc_links(
         traits_in_scope: Default::default(),
         all_trait_impls: Default::default(),
         all_macro_rules: Default::default(),
+        extern_doc_reachable: Default::default(),
+        local_doc_reachable: Default::default(),
         document_private_items,
     };
 
@@ -61,6 +64,7 @@ pub(crate) fn early_resolve_intra_doc_links(
         traits_in_scope: link_resolver.traits_in_scope,
         all_trait_impls: Some(link_resolver.all_trait_impls),
         all_macro_rules: link_resolver.all_macro_rules,
+        extern_doc_reachable: link_resolver.extern_doc_reachable,
     }
 }
 
@@ -77,6 +81,15 @@ struct EarlyDocLinkResolver<'r, 'ra> {
     traits_in_scope: DefIdMap<Vec<TraitCandidate>>,
     all_trait_impls: Vec<DefId>,
     all_macro_rules: FxHashMap<Symbol, Res<ast::NodeId>>,
+    /// This set is used as a seed for `effective_visibilities`, which are then extended by some
+    /// more items using `lib_embargo_visit_item` during doc inlining.
+    extern_doc_reachable: DefIdSet,
+    /// This is an easily identifiable superset of items added to `effective_visibilities`
+    /// using `lib_embargo_visit_item` during doc inlining.
+    /// The union of `(extern,local)_doc_reachable` is therefore a superset of
+    /// `effective_visibilities` and can be used for pruning extern impls here
+    /// in early doc link resolution.
+    local_doc_reachable: DefIdSet,
     document_private_items: bool,
 }
 
@@ -105,6 +118,10 @@ fn add_traits_in_scope(&mut self, def_id: DefId) {
         }
     }
 
+    fn is_doc_reachable(&self, def_id: DefId) -> bool {
+        self.extern_doc_reachable.contains(&def_id) || self.local_doc_reachable.contains(&def_id)
+    }
+
     /// Add traits in scope for links in impls collected by the `collect-intra-doc-links` pass.
     /// That pass filters impls using type-based information, but we don't yet have such
     /// information here, so we just conservatively calculate traits in scope for *all* modules
@@ -114,6 +131,14 @@ fn process_extern_impls(&mut self) {
         let mut start_cnum = 0;
         loop {
             let crates = Vec::from_iter(self.resolver.cstore().crates_untracked());
+            for cnum in &crates[start_cnum..] {
+                early_lib_embargo_visit_item(
+                    self.resolver,
+                    &mut self.extern_doc_reachable,
+                    cnum.as_def_id(),
+                    true,
+                );
+            }
             for &cnum in &crates[start_cnum..] {
                 let all_trait_impls =
                     Vec::from_iter(self.resolver.cstore().trait_impls_in_crate_untracked(cnum));
@@ -127,28 +152,26 @@ fn process_extern_impls(&mut self) {
                 // privacy, private traits and impls from other crates are never documented in
                 // the current crate, and links in their doc comments are not resolved.
                 for &(trait_def_id, impl_def_id, simplified_self_ty) in &all_trait_impls {
-                    if self.resolver.cstore().visibility_untracked(trait_def_id).is_public()
-                        && simplified_self_ty.and_then(|ty| ty.def()).map_or(true, |ty_def_id| {
-                            self.resolver.cstore().visibility_untracked(ty_def_id).is_public()
-                        })
+                    if self.is_doc_reachable(trait_def_id)
+                        && simplified_self_ty
+                            .and_then(|ty| ty.def())
+                            .map_or(true, |ty_def_id| self.is_doc_reachable(ty_def_id))
                     {
                         if self.visited_mods.insert(trait_def_id) {
                             self.resolve_doc_links_extern_impl(trait_def_id, false);
                         }
                         self.resolve_doc_links_extern_impl(impl_def_id, false);
                     }
+                    self.all_trait_impls.push(impl_def_id);
                 }
                 for (ty_def_id, impl_def_id) in all_inherent_impls {
-                    if self.resolver.cstore().visibility_untracked(ty_def_id).is_public() {
+                    if self.is_doc_reachable(ty_def_id) {
                         self.resolve_doc_links_extern_impl(impl_def_id, true);
                     }
                 }
                 for impl_def_id in all_incoherent_impls {
                     self.resolve_doc_links_extern_impl(impl_def_id, true);
                 }
-
-                self.all_trait_impls
-                    .extend(all_trait_impls.into_iter().map(|(_, def_id, _)| def_id));
             }
 
             if crates.len() > start_cnum {
@@ -298,6 +321,7 @@ fn process_module_children_or_reexports(&mut self, module_id: DefId) {
                     && module_id.is_local()
             {
                 if let Some(def_id) = child.res.opt_def_id() && !def_id.is_local() {
+                    self.local_doc_reachable.insert(def_id);
                     let scope_id = match child.res {
                         Res::Def(
                             DefKind::Variant
index 7158355ffdacc65b06457aa5dc55882ec6967a8e..03be5e799716706d2cccda938dff8a90d8154246 100644 (file)
@@ -19,8 +19,7 @@
 pub(crate) fn visit_item(cx: &DocContext<'_>, item: &clean::Item) {
     if let Some(dox) = &item.attrs.collapsed_doc_value() {
         let sp = item.attr_span(cx.tcx);
-        let extra =
-            crate::html::markdown::ExtraInfo::new_did(cx.tcx, item.item_id.expect_def_id(), sp);
+        let extra = crate::html::markdown::ExtraInfo::new(cx.tcx, item.item_id.expect_def_id(), sp);
         for code_block in markdown::rust_code_blocks(dox, &extra) {
             check_rust_syntax(cx, item, dox, code_block);
         }
@@ -73,7 +72,6 @@ fn check_rust_syntax(
             return;
         };
 
-    let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id);
     let empty_block = code_block.lang_string == Default::default() && code_block.is_fenced;
     let is_ignore = code_block.lang_string.ignore != markdown::Ignore::None;
 
@@ -93,6 +91,7 @@ fn check_rust_syntax(
     // Finally build and emit the completed diagnostic.
     // All points of divergence have been handled earlier so this can be
     // done the same way whether the span is precise or not.
+    let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id);
     cx.tcx.struct_span_lint_hir(crate::lint::INVALID_RUST_CODEBLOCKS, hir_id, sp, msg, |lint| {
         let explanation = if is_ignore {
             "`ignore` code blocks require valid Rust code for syntax highlighting; \
index de3a4b33905953c469e8831f8db80cd2e6e67680..a4bc486900b3e92e88e6e3262a2067f212b67de2 100644 (file)
@@ -9,6 +9,7 @@
 use crate::passes::Pass;
 
 use rustc_hir::def_id::LocalDefId;
+use rustc_middle::ty::DefIdTree;
 
 pub(crate) const PROPAGATE_DOC_CFG: Pass = Pass {
     name: "propagate-doc-cfg",
@@ -41,24 +42,22 @@ fn merge_with_parent_attributes(&mut self, item: &mut Item) {
         let Some(def_id) = item.item_id.as_def_id().and_then(|def_id| def_id.as_local())
             else { return };
 
-        let hir = self.cx.tcx.hir();
-        let hir_id = hir.local_def_id_to_hir_id(def_id);
-
         if check_parent {
-            let expected_parent = hir.get_parent_item(hir_id);
+            let expected_parent = self.cx.tcx.opt_local_parent(def_id);
             // If parents are different, it means that `item` is a reexport and we need
             // to compute the actual `cfg` by iterating through its "real" parents.
-            if self.parent == Some(expected_parent.def_id) {
+            if self.parent.is_some() && self.parent == expected_parent {
                 return;
             }
         }
 
         let mut attrs = Vec::new();
-        for (parent_hir_id, _) in hir.parent_iter(hir_id) {
-            if let Some(def_id) = hir.opt_local_def_id(parent_hir_id) {
-                attrs.extend_from_slice(load_attrs(self.cx, def_id.to_def_id()));
-            }
+        let mut next_def_id = def_id;
+        while let Some(parent_def_id) = self.cx.tcx.opt_local_parent(next_def_id) {
+            attrs.extend_from_slice(load_attrs(self.cx, parent_def_id.to_def_id()));
+            next_def_id = parent_def_id;
         }
+
         let (_, cfg) = merge_attrs(self.cx, None, item.attrs.other_attrs.as_slice(), Some(&attrs));
         item.cfg = cfg;
     }
index 00ea6ca4152c8ee460c09434fa3350911b7f950a..a89d6fa83983d685e8a6baf94d63327320beca71 100644 (file)
@@ -4,9 +4,9 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, DefIdMap};
-use rustc_hir::{HirIdSet, Node, CRATE_HIR_ID};
-use rustc_middle::ty::TyCtxt;
+use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LocalDefIdSet};
+use rustc_hir::{Node, CRATE_HIR_ID};
+use rustc_middle::ty::{DefIdTree, TyCtxt};
 use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
@@ -23,19 +23,26 @@ pub(crate) struct Module<'hir> {
     pub(crate) name: Symbol,
     pub(crate) where_inner: Span,
     pub(crate) mods: Vec<Module<'hir>>,
-    pub(crate) id: hir::HirId,
+    pub(crate) def_id: LocalDefId,
     // (item, renamed, import_id)
-    pub(crate) items: Vec<(&'hir hir::Item<'hir>, Option<Symbol>, Option<hir::HirId>)>,
+    pub(crate) items: Vec<(&'hir hir::Item<'hir>, Option<Symbol>, Option<LocalDefId>)>,
     pub(crate) foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option<Symbol>)>,
 }
 
 impl Module<'_> {
-    pub(crate) fn new(name: Symbol, id: hir::HirId, where_inner: Span) -> Self {
-        Module { name, id, where_inner, mods: Vec::new(), items: Vec::new(), foreigns: Vec::new() }
+    pub(crate) fn new(name: Symbol, def_id: LocalDefId, where_inner: Span) -> Self {
+        Module {
+            name,
+            def_id,
+            where_inner,
+            mods: Vec::new(),
+            items: Vec::new(),
+            foreigns: Vec::new(),
+        }
     }
 
     pub(crate) fn where_outer(&self, tcx: TyCtxt<'_>) -> Span {
-        tcx.hir().span(self.id)
+        tcx.def_span(self.def_id)
     }
 }
 
@@ -46,10 +53,10 @@ fn def_id_to_path(tcx: TyCtxt<'_>, did: DefId) -> Vec<Symbol> {
     std::iter::once(crate_name).chain(relative).collect()
 }
 
-pub(crate) fn inherits_doc_hidden(tcx: TyCtxt<'_>, mut node: hir::HirId) -> bool {
-    while let Some(id) = tcx.hir().get_enclosing_scope(node) {
+pub(crate) fn inherits_doc_hidden(tcx: TyCtxt<'_>, mut node: LocalDefId) -> bool {
+    while let Some(id) = tcx.opt_local_parent(node) {
         node = id;
-        if tcx.hir().attrs(node).lists(sym::doc).has_word(sym::hidden) {
+        if tcx.is_doc_hidden(node.to_def_id()) {
             return true;
         }
     }
@@ -61,7 +68,7 @@ pub(crate) fn inherits_doc_hidden(tcx: TyCtxt<'_>, mut node: hir::HirId) -> bool
 
 pub(crate) struct RustdocVisitor<'a, 'tcx> {
     cx: &'a mut core::DocContext<'tcx>,
-    view_item_stack: HirIdSet,
+    view_item_stack: LocalDefIdSet,
     inlining: bool,
     /// Are the current module and all of its parents public?
     inside_public_path: bool,
@@ -71,8 +78,8 @@ pub(crate) struct RustdocVisitor<'a, 'tcx> {
 impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
     pub(crate) fn new(cx: &'a mut core::DocContext<'tcx>) -> RustdocVisitor<'a, 'tcx> {
         // If the root is re-exported, terminate all recursion.
-        let mut stack = HirIdSet::default();
-        stack.insert(hir::CRATE_HIR_ID);
+        let mut stack = LocalDefIdSet::default();
+        stack.insert(CRATE_DEF_ID);
         RustdocVisitor {
             cx,
             view_item_stack: stack,
@@ -89,7 +96,7 @@ fn store_path(&mut self, did: DefId) {
 
     pub(crate) fn visit(mut self) -> Module<'tcx> {
         let mut top_level_module = self.visit_mod_contents(
-            hir::CRATE_HIR_ID,
+            CRATE_DEF_ID,
             self.cx.tcx.hir().root_module(),
             self.cx.tcx.crate_name(LOCAL_CRATE),
             None,
@@ -152,16 +159,15 @@ pub(crate) fn visit(mut self) -> Module<'tcx> {
 
     fn visit_mod_contents(
         &mut self,
-        id: hir::HirId,
+        def_id: LocalDefId,
         m: &'tcx hir::Mod<'tcx>,
         name: Symbol,
-        parent_id: Option<hir::HirId>,
+        parent_id: Option<LocalDefId>,
     ) -> Module<'tcx> {
-        let mut om = Module::new(name, id, m.spans.inner_span);
-        let def_id = self.cx.tcx.hir().local_def_id(id).to_def_id();
+        let mut om = Module::new(name, def_id, m.spans.inner_span);
         // Keep track of if there were any private modules in the path.
         let orig_inside_public_path = self.inside_public_path;
-        self.inside_public_path &= self.cx.tcx.visibility(def_id).is_public();
+        self.inside_public_path &= self.cx.tcx.local_visibility(def_id).is_public();
         for &i in m.item_ids {
             let item = self.cx.tcx.hir().item(i);
             if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
@@ -193,7 +199,7 @@ fn visit_mod_contents(
     /// Returns `true` if the target has been inlined.
     fn maybe_inline_local(
         &mut self,
-        id: hir::HirId,
+        def_id: LocalDefId,
         res: Res,
         renamed: Option<Symbol>,
         glob: bool,
@@ -211,10 +217,10 @@ fn maybe_inline_local(
             return false;
         };
 
-        let use_attrs = tcx.hir().attrs(id);
+        let use_attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(def_id));
         // Don't inline `doc(hidden)` imports so they can be stripped at a later stage.
         let is_no_inline = use_attrs.lists(sym::doc).has_word(sym::no_inline)
-            || use_attrs.lists(sym::doc).has_word(sym::hidden);
+            || tcx.is_doc_hidden(def_id.to_def_id());
 
         // For cross-crate impl inlining we need to know whether items are
         // reachable in documentation -- a previously unreachable item can be
@@ -225,37 +231,39 @@ fn maybe_inline_local(
             return false;
         }
 
-        let res_hir_id = match res_did.as_local() {
-            Some(n) => tcx.hir().local_def_id_to_hir_id(n),
-            None => return false,
+        let Some(res_did) = res_did.as_local() else {
+            return false;
         };
 
-        let is_private =
-            !self.cx.cache.effective_visibilities.is_directly_public(self.cx.tcx, res_did);
-        let is_hidden = inherits_doc_hidden(self.cx.tcx, res_hir_id);
+        let is_private = !self
+            .cx
+            .cache
+            .effective_visibilities
+            .is_directly_public(self.cx.tcx, res_did.to_def_id());
+        let is_hidden = inherits_doc_hidden(self.cx.tcx, res_did);
 
         // Only inline if requested or if the item would otherwise be stripped.
         if (!please_inline && !is_private && !is_hidden) || is_no_inline {
             return false;
         }
 
-        if !self.view_item_stack.insert(res_hir_id) {
+        if !self.view_item_stack.insert(res_did) {
             return false;
         }
 
-        let ret = match tcx.hir().get(res_hir_id) {
+        let ret = match tcx.hir().get_by_def_id(res_did) {
             Node::Item(&hir::Item { kind: hir::ItemKind::Mod(ref m), .. }) if glob => {
                 let prev = mem::replace(&mut self.inlining, true);
                 for &i in m.item_ids {
                     let i = self.cx.tcx.hir().item(i);
-                    self.visit_item(i, None, om, Some(id));
+                    self.visit_item(i, None, om, Some(def_id));
                 }
                 self.inlining = prev;
                 true
             }
             Node::Item(it) if !glob => {
                 let prev = mem::replace(&mut self.inlining, true);
-                self.visit_item(it, renamed, om, Some(id));
+                self.visit_item(it, renamed, om, Some(def_id));
                 self.inlining = prev;
                 true
             }
@@ -267,7 +275,7 @@ fn maybe_inline_local(
             }
             _ => false,
         };
-        self.view_item_stack.remove(&res_hir_id);
+        self.view_item_stack.remove(&res_did);
         ret
     }
 
@@ -276,7 +284,7 @@ fn visit_item(
         item: &'tcx hir::Item<'_>,
         renamed: Option<Symbol>,
         om: &mut Module<'tcx>,
-        parent_id: Option<hir::HirId>,
+        parent_id: Option<LocalDefId>,
     ) {
         debug!("visiting item {:?}", item);
         let name = renamed.unwrap_or(item.ident.name);
@@ -321,7 +329,7 @@ fn visit_item(
                         let is_glob = kind == hir::UseKind::Glob;
                         let ident = if is_glob { None } else { Some(name) };
                         if self.maybe_inline_local(
-                            item.hir_id(),
+                            item.owner_id.def_id,
                             res,
                             ident,
                             is_glob,
@@ -356,7 +364,7 @@ fn visit_item(
                 }
             }
             hir::ItemKind::Mod(ref m) => {
-                om.mods.push(self.visit_mod_contents(item.hir_id(), m, name, parent_id));
+                om.mods.push(self.visit_mod_contents(item.owner_id.def_id, m, name, parent_id));
             }
             hir::ItemKind::Fn(..)
             | hir::ItemKind::ExternCrate(..)
index fd4f9254107caee8baa3b9837b7260f115a1737b..07d8b78d767dbb956994588c01ea194007ec06f0 100644 (file)
@@ -1,7 +1,8 @@
 use crate::core::DocContext;
-use rustc_hir::def::DefKind;
+use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, DefIdSet};
 use rustc_middle::ty::TyCtxt;
+use rustc_resolve::Resolver;
 
 // FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses
 
@@ -25,6 +26,10 @@ impl RustdocEffectiveVisibilities {
     define_method!(is_directly_public);
     define_method!(is_exported);
     define_method!(is_reachable);
+
+    pub(crate) fn init(&mut self, extern_public: DefIdSet) {
+        self.extern_public = extern_public;
+    }
 }
 
 pub(crate) fn lib_embargo_visit_item(cx: &mut DocContext<'_>, def_id: DefId) {
@@ -37,6 +42,17 @@ pub(crate) fn lib_embargo_visit_item(cx: &mut DocContext<'_>, def_id: DefId) {
     .visit_item(def_id)
 }
 
+pub(crate) fn early_lib_embargo_visit_item(
+    resolver: &Resolver<'_>,
+    extern_public: &mut DefIdSet,
+    def_id: DefId,
+    is_mod: bool,
+) {
+    assert!(!def_id.is_local());
+    EarlyLibEmbargoVisitor { resolver, extern_public, visited_mods: Default::default() }
+        .visit_item(def_id, is_mod)
+}
+
 /// Similar to `librustc_privacy::EmbargoVisitor`, but also takes
 /// specific rustdoc annotations into account (i.e., `doc(hidden)`)
 struct LibEmbargoVisitor<'a, 'tcx> {
@@ -47,6 +63,14 @@ struct LibEmbargoVisitor<'a, 'tcx> {
     visited_mods: DefIdSet,
 }
 
+struct EarlyLibEmbargoVisitor<'r, 'ra> {
+    resolver: &'r Resolver<'ra>,
+    // Effective visibilities for reachable nodes
+    extern_public: &'r mut DefIdSet,
+    // Keeps track of already visited modules, in case a module re-exports its parent
+    visited_mods: DefIdSet,
+}
+
 impl LibEmbargoVisitor<'_, '_> {
     fn visit_mod(&mut self, def_id: DefId) {
         if !self.visited_mods.insert(def_id) {
@@ -71,3 +95,28 @@ fn visit_item(&mut self, def_id: DefId) {
         }
     }
 }
+
+impl EarlyLibEmbargoVisitor<'_, '_> {
+    fn visit_mod(&mut self, def_id: DefId) {
+        if !self.visited_mods.insert(def_id) {
+            return;
+        }
+
+        for item in self.resolver.cstore().module_children_untracked(def_id, self.resolver.sess()) {
+            if let Some(def_id) = item.res.opt_def_id() {
+                if item.vis.is_public() {
+                    self.visit_item(def_id, matches!(item.res, Res::Def(DefKind::Mod, _)));
+                }
+            }
+        }
+    }
+
+    fn visit_item(&mut self, def_id: DefId, is_mod: bool) {
+        if !self.resolver.cstore().is_doc_hidden_untracked(def_id) {
+            self.extern_public.insert(def_id);
+            if is_mod {
+                self.visit_mod(def_id);
+            }
+        }
+    }
+}
index 043112bbc95967dc66c3814e3d02013ff76932cf..70a80d40f464bbbd5bbabac0b0be673742b557b3 100644 (file)
@@ -7,14 +7,14 @@
 };
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
+use clippy_utils::ty::{implements_trait, is_type_lang_item};
 use if_chain::if_chain;
 use itertools::Itertools;
 use rustc_errors::{
     Applicability,
     SuggestionStyle::{CompletelyHidden, ShowCode},
 };
-use rustc_hir::{Expr, ExprKind, HirId, QPath};
+use rustc_hir::{Expr, ExprKind, HirId, LangItem, QPath};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment};
 use rustc_middle::ty::Ty;
@@ -237,7 +237,7 @@ fn check_unused_format_specifier(cx: &LateContext<'_>, arg: &FormatArg<'_>) {
         );
     }
 
-    if is_type_diagnostic_item(cx, param_ty, sym::Arguments) && !arg.format.is_default_for_trait() {
+    if is_type_lang_item(cx, param_ty, LangItem::FormatArguments) && !arg.format.is_default_for_trait() {
         span_lint_and_then(
             cx,
             UNUSED_FORMAT_SPECS,
index 77c5f1155423c4a7a4399694988e3b56442bae5a..659063b97e74a3559907622019f3ad85c4e38a5c 100644 (file)
@@ -1,6 +1,5 @@
 #![allow(clippy::similar_names)] // `expr` and `expn`
 
-use crate::is_path_diagnostic_item;
 use crate::source::snippet_opt;
 use crate::visitors::{for_each_expr, Descend};
 
@@ -8,7 +7,7 @@
 use itertools::{izip, Either, Itertools};
 use rustc_ast::ast::LitKind;
 use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, Node, QPath};
+use rustc_hir::{self as hir, Expr, ExprField, ExprKind, HirId, LangItem, Node, QPath, TyKind};
 use rustc_lexer::unescape::unescape_literal;
 use rustc_lexer::{tokenize, unescape, LiteralKind, TokenKind};
 use rustc_lint::LateContext;
@@ -439,8 +438,7 @@ fn new(args: &'tcx Expr<'tcx>, format_string_span: SpanData) -> Self {
                 // ArgumentV1::from_usize(<val>)
                 if let ExprKind::Call(callee, [val]) = expr.kind
                     && let ExprKind::Path(QPath::TypeRelative(ty, _)) = callee.kind
-                    && let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind
-                    && path.segments.last().unwrap().ident.name == sym::ArgumentV1
+                    && let TyKind::Path(QPath::LangItem(LangItem::FormatArgument, _, _)) = ty.kind
                 {
                     let val_idx = if val.span.ctxt() == expr.span.ctxt()
                         && let ExprKind::Field(_, field) = val.kind
@@ -486,20 +484,6 @@ struct ParamPosition {
 
 impl<'tcx> Visitor<'tcx> for ParamPosition {
     fn visit_expr_field(&mut self, field: &'tcx ExprField<'tcx>) {
-        fn parse_count(expr: &Expr<'_>) -> Option<usize> {
-            // ::core::fmt::rt::v1::Count::Param(1usize),
-            if let ExprKind::Call(ctor, [val]) = expr.kind
-                && let ExprKind::Path(QPath::Resolved(_, path)) = ctor.kind
-                && path.segments.last()?.ident.name == sym::Param
-                && let ExprKind::Lit(lit) = &val.kind
-                && let LitKind::Int(pos, _) = lit.node
-            {
-                Some(pos as usize)
-            } else {
-                None
-            }
-        }
-
         match field.ident.name {
             sym::position => {
                 if let ExprKind::Lit(lit) = &field.expr.kind
@@ -519,15 +503,41 @@ fn parse_count(expr: &Expr<'_>) -> Option<usize> {
     }
 }
 
+fn parse_count(expr: &Expr<'_>) -> Option<usize> {
+    // <::core::fmt::rt::v1::Count>::Param(1usize),
+    if let ExprKind::Call(ctor, [val]) = expr.kind
+        && let ExprKind::Path(QPath::TypeRelative(_, path)) = ctor.kind
+            && path.ident.name == sym::Param
+            && let ExprKind::Lit(lit) = &val.kind
+            && let LitKind::Int(pos, _) = lit.node
+    {
+        Some(pos as usize)
+    } else {
+        None
+    }
+}
+
 /// Parses the `fmt` arg of `Arguments::new_v1_formatted(pieces, args, fmt, _)`
 fn parse_rt_fmt<'tcx>(fmt_arg: &'tcx Expr<'tcx>) -> Option<impl Iterator<Item = ParamPosition> + 'tcx> {
     if let ExprKind::AddrOf(.., array) = fmt_arg.kind
         && let ExprKind::Array(specs) = array.kind
     {
         Some(specs.iter().map(|spec| {
-            let mut position = ParamPosition::default();
-            position.visit_expr(spec);
-            position
+            if let ExprKind::Call(f, args) = spec.kind
+                && let ExprKind::Path(QPath::TypeRelative(ty, f)) = f.kind
+                && let TyKind::Path(QPath::LangItem(LangItem::FormatPlaceholder, _, _)) = ty.kind
+                && f.ident.name == sym::new
+                && let [position, _fill, _align, _flags, precision, width] = args
+                && let ExprKind::Lit(position) = &position.kind
+                && let LitKind::Int(position, _) = position.node {
+                    ParamPosition {
+                        value: position as usize,
+                        width: parse_count(width),
+                        precision: parse_count(precision),
+                    }
+            } else {
+                ParamPosition::default()
+            }
         }))
     } else {
         None
@@ -701,8 +711,8 @@ pub struct FormatSpec<'tcx> {
     pub fill: Option<char>,
     /// Optionally specified alignment.
     pub align: Alignment,
-    /// Packed version of various flags provided, see [`rustc_parse_format::Flag`].
-    pub flags: u32,
+    /// Whether all flag options are set to default (no flags specified).
+    pub no_flags: bool,
     /// Represents either the maximum width or the integer precision.
     pub precision: Count<'tcx>,
     /// The minimum width, will be padded according to `width`/`align`
@@ -718,7 +728,7 @@ fn new(spec: rpf::FormatSpec<'_>, positions: ParamPosition, values: &FormatArgsV
         Some(Self {
             fill: spec.fill,
             align: spec.align,
-            flags: spec.flags,
+            no_flags: spec.sign.is_none() && !spec.alternate && !spec.zero_pad && spec.debug_hex.is_none(),
             precision: Count::new(
                 FormatParamUsage::Precision,
                 spec.precision,
@@ -763,7 +773,7 @@ pub fn is_default_for_trait(&self) -> bool {
         self.width.is_implied()
             && self.precision.is_implied()
             && self.align == Alignment::AlignUnknown
-            && self.flags == 0
+            && self.no_flags
     }
 }
 
@@ -890,7 +900,7 @@ pub fn parse(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<Self> {
         // ::core::fmt::Arguments::new_v1_formatted(pieces, args, fmt, _unsafe_arg)
         if let ExprKind::Call(callee, [pieces, args, rest @ ..]) = expr.kind
             && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind
-            && is_path_diagnostic_item(cx, ty, sym::Arguments)
+            && let TyKind::Path(QPath::LangItem(LangItem::FormatArguments, _, _)) = ty.kind
             && matches!(seg.ident.as_str(), "new_v1" | "new_v1_formatted")
         {
             let format_string = FormatString::new(cx, pieces)?;
index e7879bb196e428d3597b88d52d8d30fe83df6414..2d1044af17e8c331c0a964cb6330ff5ea2290ad4 100644 (file)
@@ -219,6 +219,7 @@ pub fn ast(
             | ast::ExprKind::Repeat(..)
             | ast::ExprKind::Ret(..)
             | ast::ExprKind::Yeet(..)
+            | ast::ExprKind::FormatArgs(..)
             | ast::ExprKind::Struct(..)
             | ast::ExprKind::Try(..)
             | ast::ExprKind::TryBlock(..)
index 0be4c3cf168cc19c833a29cc3b6e9129509d5e69..3f0f217f8907d7beba609835f913806a4a542a44 100644 (file)
@@ -400,7 +400,10 @@ fn needs_space_after_range(rhs: &ast::Expr) -> bool {
             }
         }
         ast::ExprKind::Underscore => Some("_".to_owned()),
-        ast::ExprKind::IncludedBytes(..) => unreachable!(),
+        ast::ExprKind::FormatArgs(..) | ast::ExprKind::IncludedBytes(..) => {
+            // These do not occur in the AST because macros aren't expanded.
+            unreachable!()
+        }
         ast::ExprKind::Err => None,
     };
 
index f681f55b37b9d80587610573d13ec2153060dd48..1e89f3ae75f8167b7ebfb170a0731411a65220b7 100644 (file)
@@ -463,6 +463,7 @@ pub(crate) fn first_line_ends_with(s: &str, c: char) -> bool {
 pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr: &str) -> bool {
     match expr.kind {
         ast::ExprKind::MacCall(..)
+        | ast::ExprKind::FormatArgs(..)
         | ast::ExprKind::Call(..)
         | ast::ExprKind::MethodCall(..)
         | ast::ExprKind::Array(..)
index bc2edf634de2b617b5f0c46da2c20051f379784c..8ce19c8b5145b818342fa6b5e797ab825bb5bba8 100644 (file)
@@ -59,7 +59,6 @@
     ("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"),
     "cranelift-codegen",
     "cranelift-codegen-meta",
     "cranelift-codegen-shared",
-    "cranelift-egraph",
     "cranelift-entity",
     "cranelift-frontend",
     "cranelift-isle",
     "winapi-i686-pc-windows-gnu",
     "winapi-x86_64-pc-windows-gnu",
     "windows-sys",
+    "windows_aarch64_gnullvm",
     "windows_aarch64_msvc",
     "windows_i686_gnu",
     "windows_i686_msvc",
     "windows_x86_64_gnu",
+    "windows_x86_64_gnullvm",
     "windows_x86_64_msvc",
 ];
 
index e9740e30da483d6a5231c8e47a17fe2a678d015a..bc11e1081244ad84017d516a76acf4272afab19a 100644 (file)
@@ -109,3 +109,28 @@ pub unsafe fn transmute_fn_ptr_to_data(x: fn()) -> *const () {
     // as long as it doesn't cause a verifier error by using `bitcast`.
     transmute(x)
 }
+
+pub enum Either<T, U> { A(T), B(U) }
+
+// Previously, we would codegen this as passing/returning a scalar pair of `{ i8, ptr }`,
+// with the `ptr` field representing both `&i32` and `fn()` depending on the variant.
+// This is incorrect, because `fn()` should be `ptr addrspace(1)`, not `ptr`.
+
+// CHECK: define{{.+}}void @should_not_combine_addrspace({{.+\*|ptr}}{{.+}}sret{{.+}}%0, {{.+\*|ptr}}{{.+}}%x)
+#[no_mangle]
+#[inline(never)]
+pub fn should_not_combine_addrspace(x: Either<&i32, fn()>) -> Either<&i32, fn()> {
+    x
+}
+
+// The incorrectness described above would result in us producing (after optimizations)
+// a `ptrtoint`/`inttoptr` roundtrip to convert from `ptr` to `ptr addrspace(1)`.
+
+// CHECK-LABEL: @call_with_fn_ptr
+#[no_mangle]
+pub fn call_with_fn_ptr<'a>(f: fn()) -> Either<&'a i32, fn()> {
+    // CHECK-NOT: ptrtoint
+    // CHECK-NOT: inttoptr
+    // CHECK: call addrspace(1) void @should_not_combine_addrspace
+    should_not_combine_addrspace(Either::B(f))
+}
diff --git a/tests/mir-opt/building/custom/arrays.arrays.built.after.mir b/tests/mir-opt/building/custom/arrays.arrays.built.after.mir
new file mode 100644 (file)
index 0000000..4c92127
--- /dev/null
@@ -0,0 +1,14 @@
+// MIR for `arrays` after built
+
+fn arrays() -> usize {
+    let mut _0: usize;                   // return place in scope 0 at $DIR/arrays.rs:+0:32: +0:37
+    let mut _1: [i32; C];                // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+    let mut _2: usize;                   // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        _1 = [const 5_i32; C];           // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+        _2 = Len(_1);                    // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+        _0 = _2;                         // scope 0 at $DIR/arrays.rs:+4:9: +4:16
+        return;                          // scope 0 at $DIR/arrays.rs:+5:9: +5:17
+    }
+}
diff --git a/tests/mir-opt/building/custom/arrays.rs b/tests/mir-opt/building/custom/arrays.rs
new file mode 100644 (file)
index 0000000..8e0a1fd
--- /dev/null
@@ -0,0 +1,19 @@
+#![feature(custom_mir, core_intrinsics, inline_const)]
+
+extern crate core;
+use core::intrinsics::mir::*;
+
+// EMIT_MIR arrays.arrays.built.after.mir
+#[custom_mir(dialect = "built")]
+fn arrays<const C: usize>() -> usize {
+    mir!({
+        let x = [5_i32; C];
+        let c = Len(x);
+        RET = c;
+        Return()
+    })
+}
+
+fn main() {
+    assert_eq!(arrays::<20>(), 20);
+}
index e5cd456377844e1d18ee1cde5a09ddf26fb828dc..eca5b792ec0a26ebaae0c0d4c1e07d2a2742b726 100644 (file)
@@ -86,6 +86,7 @@ fn switch_option_repr(option: Bool) -> bool {
 #[custom_mir(dialect = "runtime", phase = "initial")]
 fn set_discr(option: &mut Option<()>) {
     mir!({
+        Deinit(*option);
         SetDiscriminant(*option, 0);
         Return()
     })
index 7de9ed0983fe80a2787988eed3e541ae340a86c1..6d07473658acefad878248a707c740c5ec7eb577 100644 (file)
@@ -4,7 +4,8 @@ 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
+        Deinit((*_1));                   // scope 0 at $DIR/enums.rs:+2:9: +2:24
+        discriminant((*_1)) = 0;         // scope 0 at $DIR/enums.rs:+3:9: +3:36
+        return;                          // scope 0 at $DIR/enums.rs:+4:9: +4:17
     }
 }
diff --git a/tests/mir-opt/building/custom/operators.f.built.after.mir b/tests/mir-opt/building/custom/operators.f.built.after.mir
new file mode 100644 (file)
index 0000000..cb43d5e
--- /dev/null
@@ -0,0 +1,30 @@
+// MIR for `f` after built
+
+fn f(_1: i32, _2: bool) -> i32 {
+    let mut _0: i32;                     // return place in scope 0 at $DIR/operators.rs:+0:30: +0:33
+    let mut _3: (i32, bool);             // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+
+    bb0: {
+        _1 = Neg(_1);                    // scope 0 at $DIR/operators.rs:+2:9: +2:15
+        _2 = Not(_2);                    // scope 0 at $DIR/operators.rs:+3:9: +3:15
+        _1 = Add(_1, _1);                // scope 0 at $DIR/operators.rs:+4:9: +4:18
+        _1 = Sub(_1, _1);                // scope 0 at $DIR/operators.rs:+5:9: +5:18
+        _1 = Mul(_1, _1);                // scope 0 at $DIR/operators.rs:+6:9: +6:18
+        _1 = Div(_1, _1);                // scope 0 at $DIR/operators.rs:+7:9: +7:18
+        _1 = Rem(_1, _1);                // scope 0 at $DIR/operators.rs:+8:9: +8:18
+        _1 = BitXor(_1, _1);             // scope 0 at $DIR/operators.rs:+9:9: +9:18
+        _1 = BitAnd(_1, _1);             // scope 0 at $DIR/operators.rs:+10:9: +10:18
+        _1 = Shl(_1, _1);                // scope 0 at $DIR/operators.rs:+11:9: +11:19
+        _1 = Shr(_1, _1);                // scope 0 at $DIR/operators.rs:+12:9: +12:19
+        _2 = Eq(_1, _1);                 // scope 0 at $DIR/operators.rs:+13:9: +13:19
+        _2 = Lt(_1, _1);                 // scope 0 at $DIR/operators.rs:+14:9: +14:18
+        _2 = Le(_1, _1);                 // scope 0 at $DIR/operators.rs:+15:9: +15:19
+        _2 = Ge(_1, _1);                 // scope 0 at $DIR/operators.rs:+16:9: +16:19
+        _2 = Gt(_1, _1);                 // scope 0 at $DIR/operators.rs:+17:9: +17:18
+        _3 = CheckedAdd(_1, _1);         // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL
+        _2 = (_3.1: bool);               // scope 0 at $DIR/operators.rs:+19:9: +19:18
+        _1 = (_3.0: i32);                // scope 0 at $DIR/operators.rs:+20:9: +20:18
+        _0 = _1;                         // scope 0 at $DIR/operators.rs:+21:9: +21:16
+        return;                          // scope 0 at $DIR/operators.rs:+22:9: +22:17
+    }
+}
diff --git a/tests/mir-opt/building/custom/operators.rs b/tests/mir-opt/building/custom/operators.rs
new file mode 100644 (file)
index 0000000..db7a483
--- /dev/null
@@ -0,0 +1,31 @@
+// compile-flags: --crate-type=lib
+#![feature(custom_mir, core_intrinsics, inline_const)]
+use std::intrinsics::mir::*;
+
+// EMIT_MIR operators.f.built.after.mir
+#[custom_mir(dialect = "built")]
+pub fn f(a: i32, b: bool) -> i32 {
+    mir!({
+        a = -a;
+        b = !b;
+        a = a + a;
+        a = a - a;
+        a = a * a;
+        a = a / a;
+        a = a % a;
+        a = a ^ a;
+        a = a & a;
+        a = a << a;
+        a = a >> a;
+        b = a == a;
+        b = a < a;
+        b = a <= a;
+        b = a >= a;
+        b = a > a;
+        let res = Checked(a + a);
+        b = res.1;
+        a = res.0;
+        RET = a;
+        Return()
+    })
+}
diff --git a/tests/mir-opt/intrinsic_asserts.generic.InstCombine.diff b/tests/mir-opt/intrinsic_asserts.generic.InstCombine.diff
new file mode 100644 (file)
index 0000000..8ff64c1
--- /dev/null
@@ -0,0 +1,42 @@
+- // MIR for `generic` before InstCombine
++ // MIR for `generic` after InstCombine
+  
+  fn generic() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/intrinsic_asserts.rs:+0:21: +0:21
+      let _1: ();                          // in scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:46
+      let _2: ();                          // in scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:47
+      let _3: ();                          // in scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:60
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:46
+          _1 = assert_inhabited::<T>() -> bb1; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:46
+                                           // mir::Constant
+                                           // + span: $DIR/intrinsic_asserts.rs:25:5: 25:44
+                                           // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_inhabited::<T>}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          StorageDead(_1);                 // scope 0 at $DIR/intrinsic_asserts.rs:+1:46: +1:47
+          StorageLive(_2);                 // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:47
+          _2 = assert_zero_valid::<T>() -> bb2; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:47
+                                           // mir::Constant
+                                           // + span: $DIR/intrinsic_asserts.rs:26:5: 26:45
+                                           // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_zero_valid::<T>}, val: Value(<ZST>) }
+      }
+  
+      bb2: {
+          StorageDead(_2);                 // scope 0 at $DIR/intrinsic_asserts.rs:+2:47: +2:48
+          StorageLive(_3);                 // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:60
+          _3 = assert_mem_uninitialized_valid::<T>() -> bb3; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:60
+                                           // mir::Constant
+                                           // + span: $DIR/intrinsic_asserts.rs:27:5: 27:58
+                                           // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_mem_uninitialized_valid::<T>}, val: Value(<ZST>) }
+      }
+  
+      bb3: {
+          StorageDead(_3);                 // scope 0 at $DIR/intrinsic_asserts.rs:+3:60: +3:61
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+0:21: +4:2
+          return;                          // scope 0 at $DIR/intrinsic_asserts.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/tests/mir-opt/intrinsic_asserts.panics.InstCombine.diff b/tests/mir-opt/intrinsic_asserts.panics.InstCombine.diff
new file mode 100644 (file)
index 0000000..ddc0159
--- /dev/null
@@ -0,0 +1,47 @@
+- // MIR for `panics` before InstCombine
++ // MIR for `panics` after InstCombine
+  
+  fn panics() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/intrinsic_asserts.rs:+0:17: +0:17
+      let _1: ();                          // in scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50
+      let _2: ();                          // in scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49
+      let _3: ();                          // in scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50
+-         _1 = assert_inhabited::<Never>() -> bb1; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50
++         _1 = assert_inhabited::<Never>(); // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:50
+                                           // mir::Constant
+                                           // + span: $DIR/intrinsic_asserts.rs:17:5: 17:48
+                                           // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_inhabited::<Never>}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
+          StorageDead(_1);                 // scope 0 at $DIR/intrinsic_asserts.rs:+1:50: +1:51
+          StorageLive(_2);                 // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49
+-         _2 = assert_zero_valid::<&u8>() -> bb2; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49
++         _2 = assert_zero_valid::<&u8>(); // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:49
+                                           // mir::Constant
+                                           // + span: $DIR/intrinsic_asserts.rs:18:5: 18:47
+                                           // + user_ty: UserType(0)
+                                           // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_zero_valid::<&u8>}, val: Value(<ZST>) }
+      }
+  
+      bb2: {
+          StorageDead(_2);                 // scope 0 at $DIR/intrinsic_asserts.rs:+2:49: +2:50
+          StorageLive(_3);                 // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62
+-         _3 = assert_mem_uninitialized_valid::<&u8>() -> bb3; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62
++         _3 = assert_mem_uninitialized_valid::<&u8>(); // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:62
+                                           // mir::Constant
+                                           // + span: $DIR/intrinsic_asserts.rs:19:5: 19:60
+                                           // + user_ty: UserType(1)
+                                           // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_mem_uninitialized_valid::<&u8>}, val: Value(<ZST>) }
+      }
+  
+      bb3: {
+          StorageDead(_3);                 // scope 0 at $DIR/intrinsic_asserts.rs:+3:62: +3:63
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+0:17: +4:2
+          return;                          // scope 0 at $DIR/intrinsic_asserts.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/tests/mir-opt/intrinsic_asserts.removable.InstCombine.diff b/tests/mir-opt/intrinsic_asserts.removable.InstCombine.diff
new file mode 100644 (file)
index 0000000..568fbf1
--- /dev/null
@@ -0,0 +1,45 @@
+- // MIR for `removable` before InstCombine
++ // MIR for `removable` after InstCombine
+  
+  fn removable() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/intrinsic_asserts.rs:+0:20: +0:20
+      let _1: ();                          // in scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:47
+      let _2: ();                          // in scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:48
+      let _3: ();                          // in scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:47
+-         _1 = assert_inhabited::<()>() -> bb1; // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:47
+-                                          // mir::Constant
+-                                          // + span: $DIR/intrinsic_asserts.rs:7:5: 7:45
+-                                          // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_inhabited::<()>}, val: Value(<ZST>) }
++         goto -> bb1;                     // scope 0 at $DIR/intrinsic_asserts.rs:+1:5: +1:47
+      }
+  
+      bb1: {
+          StorageDead(_1);                 // scope 0 at $DIR/intrinsic_asserts.rs:+1:47: +1:48
+          StorageLive(_2);                 // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:48
+-         _2 = assert_zero_valid::<u8>() -> bb2; // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:48
+-                                          // mir::Constant
+-                                          // + span: $DIR/intrinsic_asserts.rs:8:5: 8:46
+-                                          // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_zero_valid::<u8>}, val: Value(<ZST>) }
++         goto -> bb2;                     // scope 0 at $DIR/intrinsic_asserts.rs:+2:5: +2:48
+      }
+  
+      bb2: {
+          StorageDead(_2);                 // scope 0 at $DIR/intrinsic_asserts.rs:+2:48: +2:49
+          StorageLive(_3);                 // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61
+-         _3 = assert_mem_uninitialized_valid::<u8>() -> bb3; // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61
+-                                          // mir::Constant
+-                                          // + span: $DIR/intrinsic_asserts.rs:9:5: 9:59
+-                                          // + literal: Const { ty: extern "rust-intrinsic" fn() {assert_mem_uninitialized_valid::<u8>}, val: Value(<ZST>) }
++         goto -> bb3;                     // scope 0 at $DIR/intrinsic_asserts.rs:+3:5: +3:61
+      }
+  
+      bb3: {
+          StorageDead(_3);                 // scope 0 at $DIR/intrinsic_asserts.rs:+3:61: +3:62
+          nop;                             // scope 0 at $DIR/intrinsic_asserts.rs:+0:20: +4:2
+          return;                          // scope 0 at $DIR/intrinsic_asserts.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/tests/mir-opt/intrinsic_asserts.rs b/tests/mir-opt/intrinsic_asserts.rs
new file mode 100644 (file)
index 0000000..8fb99cd
--- /dev/null
@@ -0,0 +1,28 @@
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+// All these assertions pass, so all the intrinsic calls should be deleted.
+// EMIT_MIR intrinsic_asserts.removable.InstCombine.diff
+pub fn removable() {
+    core::intrinsics::assert_inhabited::<()>();
+    core::intrinsics::assert_zero_valid::<u8>();
+    core::intrinsics::assert_mem_uninitialized_valid::<u8>();
+}
+
+enum Never {}
+
+// These assertions all diverge, so their target blocks should become None.
+// EMIT_MIR intrinsic_asserts.panics.InstCombine.diff
+pub fn panics() {
+    core::intrinsics::assert_inhabited::<Never>();
+    core::intrinsics::assert_zero_valid::<&u8>();
+    core::intrinsics::assert_mem_uninitialized_valid::<&u8>();
+}
+
+// Whether or not these asserts pass isn't known, so they shouldn't be modified.
+// EMIT_MIR intrinsic_asserts.generic.InstCombine.diff
+pub fn generic<T>() {
+    core::intrinsics::assert_inhabited::<T>();
+    core::intrinsics::assert_zero_valid::<T>();
+    core::intrinsics::assert_mem_uninitialized_valid::<T>();
+}
index 3af37955f238079de77ae656b08b2694d33ba5ba..60fddb630d964d72bfdcbb0b32c0bb768a192e54 100644 (file)
@@ -8,6 +8,4 @@ extern crate std;
 // pretty-mode:expanded
 // pp-exact:dollar-crate.pp
 
-fn main() {
-    { ::std::io::_print(::core::fmt::Arguments::new_v1(&["rust\n"], &[])); };
-}
+fn main() { { ::std::io::_print(format_args!("rust\n")); }; }
index 18e6d75b1d5ad05a60a3d87f3e33a29d4618ab12..44d21625a2d108a2e14e966d2e14328215adfa7b 100644 (file)
@@ -32,7 +32,7 @@ fn bar() ({
         ({
                 let res =
                     ((::alloc::fmt::format as
-                            for<'a> fn(Arguments<'a>) -> String {format})(((::core::fmt::Arguments::new_v1
+                            for<'a> fn(Arguments<'a>) -> String {format})(((<#[lang = "format_arguments"]>::new_v1
                                 as
                                 fn(&[&'static str], &[ArgumentV1<'_>]) -> Arguments<'_> {Arguments::<'_>::new_v1})((&([("test"
                                             as &str)] as [&str; 1]) as &[&str; 1]),
index 1831ab38fab49d9728505491e3d15e4e9b653773..44cda0d3d117f8bfec9ff71bea889ee811153ba2 100644 (file)
@@ -254,12 +254,12 @@ unpacked-remapped-single:
        $(RUSTC) $(UNSTABLEOPTS) -C split-debuginfo=unpacked -C debuginfo=2 \
                -Z split-dwarf-kind=single --remap-path-prefix $(TMPDIR)=/a foo.rs -g
        objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
-       ls $(TMPDIR)/*.o
+       rm $(TMPDIR)/*.o
        ls $(TMPDIR)/*.dwo && exit 1 || exit 0
        ls $(TMPDIR)/*.dwp && exit 1 || exit 0
        rm $(TMPDIR)/$(call BIN,foo)
 
-unpacked-crosscrate: packed-crosscrate-split packed-crosscrate-single
+unpacked-crosscrate: unpacked-crosscrate-split unpacked-crosscrate-single
 
 # - Debuginfo in `.dwo` files
 # - (bar) `.rlib` file created, contains `.dwo`
diff --git a/tests/run-make/overwrite-input/Makefile b/tests/run-make/overwrite-input/Makefile
new file mode 100644 (file)
index 0000000..03b03eb
--- /dev/null
@@ -0,0 +1,13 @@
+include ../../run-make-fulldeps/tools.mk
+
+all:
+       $(RUSTC) main.rs -o main.rs 2> $(TMPDIR)/file.stderr || echo "failed successfully"
+       $(RUSTC) main.rs -o . 2> $(TMPDIR)/folder.stderr || echo "failed successfully"
+
+ifdef RUSTC_BLESS_TEST
+       cp "$(TMPDIR)"/file.stderr file.stderr
+       cp "$(TMPDIR)"/folder.stderr folder.stderr
+else
+       $(DIFF) file.stderr "$(TMPDIR)"/file.stderr
+       $(DIFF) folder.stderr "$(TMPDIR)"/folder.stderr
+endif
diff --git a/tests/run-make/overwrite-input/file.stderr b/tests/run-make/overwrite-input/file.stderr
new file mode 100644 (file)
index 0000000..9936962
--- /dev/null
@@ -0,0 +1,6 @@
+warning: ignoring --out-dir flag due to -o flag
+
+error: the input file "main.rs" would be overwritten by the generated executable
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/tests/run-make/overwrite-input/folder.stderr b/tests/run-make/overwrite-input/folder.stderr
new file mode 100644 (file)
index 0000000..81b1e73
--- /dev/null
@@ -0,0 +1,6 @@
+warning: ignoring --out-dir flag due to -o flag
+
+error: the generated executable for the input file "main.rs" conflicts with the existing directory "."
+
+error: aborting due to previous error; 1 warning emitted
+
diff --git a/tests/run-make/overwrite-input/main.rs b/tests/run-make/overwrite-input/main.rs
new file mode 100644 (file)
index 0000000..f328e4d
--- /dev/null
@@ -0,0 +1 @@
+fn main() {}
diff --git a/tests/run-make/overwrite-input/main.stderr b/tests/run-make/overwrite-input/main.stderr
new file mode 100644 (file)
index 0000000..9936962
--- /dev/null
@@ -0,0 +1,6 @@
+warning: ignoring --out-dir flag due to -o flag
+
+error: the input file "main.rs" would be overwritten by the generated executable
+
+error: aborting due to previous error; 1 warning emitted
+
index 05f8ddc716e8703b6bcadd675c04b83dbd6fc568..3f4f65890b422aa83e1e5f250e848886e4d74c12 100644 (file)
@@ -20,7 +20,7 @@ assert-css: (
 // table like view
 assert-css: (".item-right.docblock-short", { "padding-left": "0px" })
 compare-elements-position-near: (
-    "//*[@class='item-left module-item']//a[text()='replaced_function']",
+    "//*[@class='item-left']//a[text()='replaced_function']",
     ".item-left .stab.deprecated",
     {"y": 2},
 )
@@ -32,7 +32,7 @@ compare-elements-position: (
 
 // Ensure no wrap
 compare-elements-position: (
-    "//*[@class='item-left module-item']//a[text()='replaced_function']/..",
+    "//*[@class='item-left']//a[text()='replaced_function']/..",
     "//*[@class='item-right docblock-short'][text()='a thing with a label']",
     ("y"),
 )
@@ -43,7 +43,7 @@ size: (600, 600)
 // staggered layout with 2em spacing
 assert-css: (".item-right.docblock-short", { "padding-left": "32px" })
 compare-elements-position-near: (
-    "//*[@class='item-left module-item']//a[text()='replaced_function']",
+    "//*[@class='item-left']//a[text()='replaced_function']",
     ".item-left .stab.deprecated",
     {"y": 2},
 )
@@ -55,7 +55,7 @@ compare-elements-position: (
 
 // Ensure wrap
 compare-elements-position-false: (
-    "//*[@class='item-left module-item']//a[text()='replaced_function']/..",
+    "//*[@class='item-left']//a[text()='replaced_function']/..",
     "//*[@class='item-right docblock-short'][text()='a thing with a label']",
     ("y"),
 )
index cd3676a9871385703857de8edc0061c351a8a96f..5940962a8ddba7a338234d3789c079e5987dc32e 100644 (file)
@@ -1,7 +1,7 @@
 // This test checks that the correct font is used on module items (in index.html pages).
 goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
 assert-css: (
-    ".item-table .module-item a",
+    ".item-table .item-left > a",
     {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
     ALL,
 )
index d3a672ddde6e491250e4022c1c7a1a5ee3be4bbc..3ecb25c82a44e133aa44209904eb871967590478 100644 (file)
@@ -4,8 +4,8 @@ goto: "file://" + |DOC_PATH| + "/test_docs/index.html"
 show-text: true
 
 compare-elements-property: (
-    "//a[@title='test_docs::safe_fn fn']/..",
-    "//a[@title='test_docs::unsafe_fn fn']/..",
+    "//a[@title='fn test_docs::safe_fn']/..",
+    "//a[@title='fn test_docs::unsafe_fn']/..",
     ["clientHeight"]
 )
 
index addb6709db1da8a25fe823eda5029fa7a057e8d5..89c7f0a6f342c4814379c6c18ba4e270c15b0ef1 100644 (file)
@@ -5,8 +5,8 @@
 #![no_core]
 
 // @has 'foo/index.html'
-// @has - '//*[@class="item-left module-item"]/*[@class="stab portability"]' 'foobar'
-// @has - '//*[@class="item-left module-item"]/*[@class="stab portability"]' 'bar'
+// @has - '//*[@class="item-left"]/*[@class="stab portability"]' 'foobar'
+// @has - '//*[@class="item-left"]/*[@class="stab portability"]' 'bar'
 
 #[doc(cfg(feature = "foobar"))]
 mod imp_priv {
index b3178da98eeb282ecc836c22b5b57937b717451d..5cbe4d59108a4208cf4d828322a43fe41edc94a3 100644 (file)
@@ -1,4 +1,4 @@
-// @has deprecated/index.html '//*[@class="item-left module-item"]/span[@class="stab deprecated"]' \
+// @has deprecated/index.html '//*[@class="item-left"]/span[@class="stab deprecated"]' \
 //      'Deprecated'
 // @has - '//*[@class="item-right docblock-short"]' 'Deprecated docs'
 
index 4cddb0b76d410125eb708e69f86a433156642fdb..1cfbfec6fcd3012e0a847fbaf5a966ee9d0ddf07 100644 (file)
@@ -12,7 +12,7 @@
 // @has doc_cfg/unix_only/index.html \
 //  '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
 //  'Available on Unix only.'
-// @matches - '//*[@class="item-left module-item"]//*[@class="stab portability"]' '\AARM\Z'
+// @matches - '//*[@class="item-left"]//*[@class="stab portability"]' '\AARM\Z'
 // @count - '//*[@class="stab portability"]' 2
 #[doc(cfg(unix))]
 pub mod unix_only {
@@ -42,7 +42,7 @@ fn unix_and_arm_only_function() {}
 // @has doc_cfg/wasi_only/index.html \
 //  '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
 //  'Available on WASI only.'
-// @matches - '//*[@class="item-left module-item"]//*[@class="stab portability"]' '\AWebAssembly\Z'
+// @matches - '//*[@class="item-left"]//*[@class="stab portability"]' '\AWebAssembly\Z'
 // @count - '//*[@class="stab portability"]' 2
 #[doc(cfg(target_os = "wasi"))]
 pub mod wasi_only {
@@ -74,7 +74,7 @@ fn wasi_and_wasm32_only_function() {}
 
 // the portability header is different on the module view versus the full view
 // @has doc_cfg/index.html
-// @matches - '//*[@class="item-left module-item"]//*[@class="stab portability"]' '\Aavx\Z'
+// @matches - '//*[@class="item-left"]//*[@class="stab portability"]' '\Aavx\Z'
 
 // @has doc_cfg/fn.uses_target_feature.html
 // @has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
index 18f3900b263b0b7617def5151e60c43519be7d5f..1ac2e52324964a6d40a35a3fa8bbceb489bca114 100644 (file)
@@ -2,8 +2,8 @@
 #![feature(doc_cfg)]
 
 // @has 'foo/index.html'
-// @matches '-' '//*[@class="item-left module-item"]//*[@class="stab portability"]' '^sync$'
-// @has '-' '//*[@class="item-left module-item"]//*[@class="stab portability"]/@title' 'Available on crate feature `sync` only'
+// @matches '-' '//*[@class="item-left"]//*[@class="stab portability"]' '^sync$'
+// @has '-' '//*[@class="item-left"]//*[@class="stab portability"]/@title' 'Available on crate feature `sync` only'
 
 // @has 'foo/struct.Foo.html'
 // @has '-' '//*[@class="stab portability"]' 'sync'
index 66a31c42bcfc7732b52c30387c2cc108eb8154c9..2668b3334979072b15b07e62cb01acba9ca74dab 100644 (file)
@@ -1,5 +1,5 @@
 // @has 'glob_shadowing/index.html'
-// @count - '//div[@class="item-left module-item"]' 6
+// @count - '//div[@class="item-left"]' 6
 // @!has - '//div[@class="item-right docblock-short"]' 'sub1::describe'
 // @has - '//div[@class="item-right docblock-short"]' 'sub2::describe'
 
index 5daa0d4baad6316e25d9cbee998146057771afb3..d5b0de5725bce4f32502d5a7be169517a361cc67 100644 (file)
@@ -6,9 +6,9 @@
 
 extern crate macros;
 
-// @has foo/index.html '//*[@class="item-left unstable deprecated module-item"]/span[@class="stab deprecated"]' \
+// @has foo/index.html '//*[@class="item-left unstable deprecated"]/span[@class="stab deprecated"]' \
 //         Deprecated
-// @has - '//*[@class="item-left unstable deprecated module-item"]/span[@class="stab unstable"]' \
+// @has - '//*[@class="item-left unstable deprecated"]/span[@class="stab unstable"]' \
 //         Experimental
 
 // @has foo/macro.my_macro.html
index 8d2c27cf3d77dc4f40cc75fc9f98cde9c0562cf7..8296d7a81f2b1bc9c49d8d2995e8b030e6a70ca0 100644 (file)
@@ -2,9 +2,9 @@
 #![doc(issue_tracker_base_url = "https://issue_url/")]
 #![unstable(feature = "test", issue = "32374")]
 
-// @matches issue_32374/index.html '//*[@class="item-left unstable deprecated module-item"]/span[@class="stab deprecated"]' \
+// @matches issue_32374/index.html '//*[@class="item-left unstable deprecated"]/span[@class="stab deprecated"]' \
 //      'Deprecated'
-// @matches issue_32374/index.html '//*[@class="item-left unstable deprecated module-item"]/span[@class="stab unstable"]' \
+// @matches issue_32374/index.html '//*[@class="item-left unstable deprecated"]/span[@class="stab unstable"]' \
 //      'Experimental'
 // @matches issue_32374/index.html '//*[@class="item-right docblock-short"]/text()' 'Docs'
 
index 14a6f5041f2085a6d5ba9f3c8025626d87627d39..b987da30ed29025994221a2ac04dc4cb14946738 100644 (file)
@@ -29,8 +29,8 @@ pub fn bar() {}
 // @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="../fn.foo.html"]' 'foo'
 // @has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="../fn.bar.html"]' 'bar'
 // Though there should be such links later
-// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-left module-item"]/a[@class="fn"][@href="fn.foo.html"]' 'foo'
-// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-left module-item"]/a[@class="fn"][@href="fn.bar.html"]' 'bar'
+// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-left"]/a[@class="fn"][@href="fn.foo.html"]' 'foo'
+// @has - '//section[@id="main-content"]/div[@class="item-table"]//div[@class="item-left"]/a[@class="fn"][@href="fn.bar.html"]' 'bar'
 /// See either [foo] or [bar].
 pub mod subtwo {
 
index d3a7a870b580a29d47a4bd3f927962744fad3344..9bce25846d8585dfb35ee558385219a80e812741 100644 (file)
@@ -11,6 +11,6 @@ pub mod prelude {
 #[doc(inline)]
 pub use sub::*;
 
-// @count foo/index.html '//a[@class="mod"][@title="foo::prelude mod"]' 1
+// @count foo/index.html '//a[@class="mod"][@title="mod foo::prelude"]' 1
 // @count foo/prelude/index.html '//div[@class="item-row"]' 0
 pub mod prelude {}
index b836925099364598de36ee0cc1b0ebeb93abc234..d0960dfef436246d1db5206def4790b291b91925 100644 (file)
@@ -8,7 +8,7 @@ pub mod prelude {
     }
 }
 
-// @count foo/index.html '//a[@class="mod"][@title="foo::prelude mod"]' 1
+// @count foo/index.html '//a[@class="mod"][@title="mod foo::prelude"]' 1
 // @count foo/prelude/index.html '//div[@class="item-row"]' 0
 pub mod prelude {}
 
index ff33fb63a0bab20208d3ca2bcb7ac59785a0caa5..3df93eb7cf16f22b81647f079d36f93003f93be8 100644 (file)
@@ -1,2 +1,2 @@
-// @has issue_95873/index.html "//*[@class='item-left import-item']" "pub use ::std as x;"
+// @has issue_95873/index.html "//*[@class='item-left']" "pub use ::std as x;"
 pub use ::std as x;
index 41e64726a3246f083267660a677401a2698236ab..ba29a77ebdff8ab41cd2beeaf1490740be4256cc 100644 (file)
@@ -9,6 +9,6 @@
 
 pub use issue_99221_aux::*;
 
-// @count foo/index.html '//a[@class="struct"][@title="foo::Print struct"]' 1
+// @count foo/index.html '//a[@class="struct"][@title="struct foo::Print"]' 1
 
 pub struct Print;
index 3208fea05b3762d05f0943e39de8ee50609aa942..b56ec6e11eafc138dfe8897ef57c64a7aee065d2 100644 (file)
@@ -9,7 +9,7 @@
 
 pub use issue_99734_aux::*;
 
-// @count foo/index.html '//a[@class="fn"][@title="foo::main fn"]' 1
+// @count foo/index.html '//a[@class="fn"][@title="fn foo::main"]' 1
 
 extern "C" {
     pub fn main() -> std::ffi::c_int;
index b2f9b8b46578b870bf91eba1eafdd39654e67f5d..8f5d6fa3d56d366c37f74ff988dbc4d720383c43 100644 (file)
@@ -9,6 +9,6 @@
 
 pub use issue_99734_aux::*;
 
-// @count foo/index.html '//a[@class="mod"][@title="foo::task mod"]' 1
+// @count foo/index.html '//a[@class="mod"][@title="mod foo::task"]' 1
 
 pub mod task {}
index 69c89626539319edb39ab24a482171ed24b8ffca..f3811fe0b0ad10781e70e9896016763f0e4886af 100644 (file)
@@ -10,4 +10,4 @@
 pub fn dummy() {}
 
 // ensure that `extern crate foo;` was inserted into code snips automatically:
-// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0Aextern%20crate%20r%23foo%3B%0Afn%20main()%20%7B%0Ause%20foo%3A%3Adummy%3B%0Adummy()%3B%0A%7D&edition=2015"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0Aextern+crate+r%23foo;%0Afn+main()+%7B%0Ause+foo::dummy;%0Adummy();%0A%7D&edition=2015"]' "Run"
index 877ea1cfba15a83cfdd6a1b2fc8c09d087547f45..5c7fa33efc5e586a3be143e52174149497279edb 100644 (file)
@@ -22,6 +22,6 @@
 //! }
 //! ```
 
-// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D&edition=2015"]' "Run"
-// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn%20main()%20%7B%0Aprintln!(%22Hello%2C%20world!%22)%3B%0A%7D&edition=2015"]' "Run"
-// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D&version=nightly&edition=2015"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0Aprintln!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&version=nightly&edition=2015"]' "Run"
index db1f90c69997855b7ad6ad078104eb484f98d8d5..acac0c9919716b067e8b4a7ffdc30e51beebdeba 100644 (file)
@@ -4,12 +4,12 @@
 extern crate reexport_check;
 
 // @!has 'foo/index.html' '//code' 'pub use self::i32;'
-// @has 'foo/index.html' '//div[@class="item-left deprecated module-item"]' 'i32'
+// @has 'foo/index.html' '//div[@class="item-left deprecated"]' 'i32'
 // @has 'foo/i32/index.html'
 #[allow(deprecated, deprecated_in_future)]
 pub use std::i32;
 // @!has 'foo/index.html' '//code' 'pub use self::string::String;'
-// @has 'foo/index.html' '//div[@class="item-left module-item"]' 'String'
+// @has 'foo/index.html' '//div[@class="item-left"]' 'String'
 pub use std::string::String;
 
 // @has 'foo/index.html' '//div[@class="item-right docblock-short"]' 'Docs in original'
index 505751969b623168fdc168c8ce5829c194300cdd..f263809552fdf3d88a0af7c0cadc9238a85b2ab8 100644 (file)
@@ -44,4 +44,18 @@ impl AssocConst for () {
     const C: Self::Ty = 0u8;
 }
 
+pub trait Trait {
+    type Res = isize; //~ NOTE associated type defaults can't be assumed inside the trait defining them
+
+    fn infer_me_correctly() -> Self::Res {
+        //~^ NOTE expected `<Self as Trait>::Res` because of return type
+
+        // {integer} == isize
+        2
+        //~^ ERROR mismatched types
+        //~| NOTE expected associated type, found integer
+        //~| NOTE expected associated type `<Self as Trait>::Res`
+    }
+}
+
 fn main() {}
index 71d421926e702f0b0b3a4786833392ff1f3a9c37..bdcfadd3955d26d39632304f4e2cd5cd245bb125 100644 (file)
@@ -24,6 +24,21 @@ LL |     const C: Self::Ty = 0u8;
    = note: expected associated type `<Self as AssocConst>::Ty`
                          found type `u8`
 
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+  --> $DIR/defaults-in-other-trait-items.rs:54:9
+   |
+LL |     type Res = isize;
+   |     ----------------- associated type defaults can't be assumed inside the trait defining them
+LL |
+LL |     fn infer_me_correctly() -> Self::Res {
+   |                                --------- expected `<Self as Trait>::Res` because of return type
+...
+LL |         2
+   |         ^ expected associated type, found integer
+   |
+   = note: expected associated type `<Self as Trait>::Res`
+                         found type `{integer}`
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
index 74411008c9dda6f74a2a64cb1dd13247d6dd4dc0..977620d9052f271b37244490edf6d8c311cdaf21 100644 (file)
@@ -1,13 +1,13 @@
 error[E0308]: mismatched types
   --> $DIR/issue-26681.rs:17:39
    |
+LL |     type Fv: Foo = u8;
+   |     ------------------ associated type defaults can't be assumed inside the trait defining them
 LL |     const C: <Self::Fv as Foo>::Bar = 6665;
    |                                       ^^^^ expected associated type, found integer
    |
    = note: expected associated type `<<Self as Baz>::Fv as Foo>::Bar`
                          found type `{integer}`
-   = help: consider constraining the associated type `<<Self as Baz>::Fv as Foo>::Bar` to `{integer}`
-   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
 
 error: aborting due to previous error
 
index 1b776322aaa647c24a32645894483ac651ac2a93..aaa8b169583fd667d723ea93d733ccd262f66ee3 100644 (file)
@@ -15,12 +15,7 @@ LL | bug!();
    |
    = note: this error originates in the macro `bug` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: unexpected expression: `{
-               let res =
-                   ::alloc::fmt::format(::core::fmt::Arguments::new_v1(&[""],
-                           &[::core::fmt::ArgumentV1::new_display(&"u8")]));
-               res
-           }.as_str()`
+error: unexpected expression: `{ let res = ::alloc::fmt::format(format_args!("{0}", "u8")); res }.as_str()`
   --> $DIR/key-value-expansion.rs:48:23
    |
 LL |         doc_comment! {format!("{coor}", coor = stringify!($t1)).as_str()}
index 50eee1049db6e479e2c827046b8f484927995f4c..5835f06753bb11242967e095fead9a0a55b747b6 100644 (file)
@@ -4,8 +4,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |         ref foo @ [.., ref mut bar] => (),
    |         -------^^^^^^^^-----------^
    |         |              |
-   |         |              mutable borrow, by `bar`, occurs here
-   |         immutable borrow, by `foo`, occurs here
+   |         |              value is mutably borrowed by `bar` here
+   |         value is borrowed by `foo` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:120:9
@@ -13,8 +13,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |         ref foo @ Some(box ref mut s) => (),
    |         -------^^^^^^^^^^^^---------^
    |         |                  |
-   |         |                  mutable borrow, by `s`, occurs here
-   |         immutable borrow, by `foo`, occurs here
+   |         |                  value is mutably borrowed by `s` here
+   |         value is borrowed by `foo` here
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:18:5
diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.rs b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.rs
new file mode 100644 (file)
index 0000000..83366ea
--- /dev/null
@@ -0,0 +1,9 @@
+// Check that even though Cell: DispatchFromDyn it remains an invalid self parameter type
+
+use std::cell::Cell;
+
+trait Trait{
+    fn cell(self: Cell<&Self>); //~ ERROR invalid `self` parameter type: Cell<&Self>
+}
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.stderr b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-cell.stderr
new file mode 100644 (file)
index 0000000..ce06ce9
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0307]: invalid `self` parameter type: Cell<&Self>
+  --> $DIR/feature-gate-dispatch-from-dyn-cell.rs:6:19
+   |
+LL |     fn cell(self: Cell<&Self>);
+   |                   ^^^^^^^^^^^
+   |
+   = note: type of `self` must be `Self` or a type that dereferences to it
+   = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0307`.
diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs
new file mode 100644 (file)
index 0000000..23857cb
--- /dev/null
@@ -0,0 +1,35 @@
+// Check that a self parameter type requires a DispatchFromDyn impl to be object safe
+
+#![feature(arbitrary_self_types, unsize, coerce_unsized)]
+
+use std::{
+    marker::Unsize,
+    ops::{CoerceUnsized, Deref},
+};
+
+struct Ptr<T: ?Sized>(Box<T>);
+
+impl<T: ?Sized> Deref for Ptr<T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        &*self.0
+    }
+}
+
+impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {}
+// Because this impl is missing the coercion below fails.
+// impl<T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T> {}
+
+trait Trait {
+    fn ptr(self: Ptr<Self>);
+}
+impl Trait for i32 {
+    fn ptr(self: Ptr<Self>) {}
+}
+
+fn main() {
+    Ptr(Box::new(4)) as Ptr<dyn Trait>;
+    //~^ ERROR the trait `Trait` cannot be made into an object
+    //~^^ ERROR the trait `Trait` cannot be made into an object
+}
diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr
new file mode 100644 (file)
index 0000000..d81eade
--- /dev/null
@@ -0,0 +1,45 @@
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:32:25
+   |
+LL |     fn ptr(self: Ptr<Self>);
+   |                  --------- help: consider changing method `ptr`'s `self` parameter to be `&self`: `&Self`
+...
+LL |     Ptr(Box::new(4)) as Ptr<dyn Trait>;
+   |                         ^^^^^^^^^^^^^^ `Trait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18
+   |
+LL | trait Trait {
+   |       ----- this trait cannot be made into an object...
+LL |     fn ptr(self: Ptr<Self>);
+   |                  ^^^^^^^^^ ...because method `ptr`'s `self` parameter cannot be dispatched on
+
+error[E0038]: the trait `Trait` cannot be made into an object
+  --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:32:5
+   |
+LL |     fn ptr(self: Ptr<Self>);
+   |                  --------- help: consider changing method `ptr`'s `self` parameter to be `&self`: `&Self`
+...
+LL |     Ptr(Box::new(4)) as Ptr<dyn Trait>;
+   |     ^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18
+   |
+LL | trait Trait {
+   |       ----- this trait cannot be made into an object...
+LL |     fn ptr(self: Ptr<Self>);
+   |                  ^^^^^^^^^ ...because method `ptr`'s `self` parameter cannot be dispatched on
+note: required for `Ptr<{integer}>` to implement `CoerceUnsized<Ptr<dyn Trait>>`
+  --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:20:40
+   |
+LL | impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {}
+   |         ---------                      ^^^^^^^^^^^^^^^^^^^^^     ^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+   = note: required by cast to type `Ptr<dyn Trait>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
index f247ff6cf3f559f7be5bc07a5e5efccac9bd2147..b4e71e75fdb9a196a556be0afb8eafffd5bf869d 100644 (file)
@@ -20,6 +20,7 @@ LL |     let x = f == g;
    = note: expected fn item `fn() {f}`
               found fn item `fn() {g}`
    = note: different fn items have unique types, even if their signatures are the same
+   = help: consider casting both fn items to fn pointers using `as fn()`
 
 error: aborting due to 2 previous errors
 
index cb1b88c7ab8f3519352fb4fb715d0f4c0fc95a5b..9d41243ef11917479aca7c97468b5e5768578352 100644 (file)
@@ -14,6 +14,7 @@ note: function defined here
    |
 LL | fn eq<T>(x: T, y: T) {}
    |    ^^          ----
+   = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:29:19
@@ -31,6 +32,7 @@ note: function defined here
    |
 LL | fn eq<T>(x: T, y: T) {}
    |    ^^          ----
+   = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:34:23
@@ -48,6 +50,7 @@ note: function defined here
    |
 LL | fn eq<T>(x: T, y: T) {}
    |    ^^          ----
+   = help: consider casting both fn items to fn pointers using `as fn(isize) -> isize`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:41:26
@@ -65,6 +68,7 @@ note: function defined here
    |
 LL | fn eq<T>(x: T, y: T) {}
    |    ^^          ----
+   = help: consider casting both fn items to fn pointers using `as fn()`
 
 error[E0308]: mismatched types
   --> $DIR/fn-item-type.rs:46:19
@@ -76,7 +80,7 @@ LL |     eq(foo::<u8>, bar::<u8> as fn(isize) -> isize);
    |
    = note: expected fn item `fn(_) -> _ {foo::<u8>}`
            found fn pointer `fn(_) -> _`
-   = note: fn items are distinct from fn pointers
+   = help: consider casting the fn item to a fn pointer: `foo::<u8> as fn(isize) -> isize`
 note: function defined here
   --> $DIR/fn-item-type.rs:11:4
    |
index 2dc0710e27e4660a6f8ce6ee28018d463c1d6b12..e0bd60fbc0b5ececeb825f217bc42413b073d26d 100644 (file)
@@ -9,6 +9,7 @@ LL |     let g = if n % 2 == 0 { &foo } else { &bar };
    = note: expected reference `&fn(u32) -> u32 {foo}`
               found reference `&fn(u32) -> u32 {bar}`
    = note: different fn items have unique types, even if their signatures are the same
+   = help: consider casting both fn items to fn pointers using `as fn(u32) -> u32`
 
 error[E0308]: mismatched types
   --> $DIR/fn-pointer-mismatch.rs:23:9
@@ -21,6 +22,7 @@ LL |     a = bar;
    = note: expected fn item `fn(_) -> _ {foo}`
               found fn item `fn(_) -> _ {bar}`
    = note: different fn items have unique types, even if their signatures are the same
+   = help: consider casting both fn items to fn pointers using `as fn(u32) -> u32`
 
 error[E0308]: mismatched types
   --> $DIR/fn-pointer-mismatch.rs:31:18
@@ -35,6 +37,7 @@ LL |     b = Box::new(bar);
    = note: different fn items have unique types, even if their signatures are the same
 note: associated function defined here
   --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+   = help: consider casting both fn items to fn pointers using `as fn(u32) -> u32`
 
 error[E0308]: mismatched types
   --> $DIR/fn-pointer-mismatch.rs:36:29
diff --git a/tests/ui/io-checks/inaccessbile-temp-dir.rs b/tests/ui/io-checks/inaccessbile-temp-dir.rs
new file mode 100644 (file)
index 0000000..9c0aa01
--- /dev/null
@@ -0,0 +1,39 @@
+// Issue #66530: We would ICE if someone compiled with `-o /dev/null`,
+// because we would try to generate auxiliary files in `/dev/` (which
+// at least the OS X file system rejects).
+//
+// An attempt to `-o` into a directory we cannot write into should indeed
+// be an error; but not an ICE.
+//
+// However, some folks run tests as root, which can write `/dev/` and end
+// up clobbering `/dev/null`. Instead we'll use a non-existent path, which
+// also used to ICE, but even root can't magically write there.
+
+// compile-flags: -Z temps-dir=/does-not-exist/output
+
+// The error-pattern check occurs *before* normalization, and the error patterns
+// are wildly different between build environments. So this is a cop-out (and we
+// rely on the checking of the normalized stderr output as our actual
+// "verification" of the diagnostic).
+
+// error-pattern: error
+
+// On Mac OS X, we get an error like the below
+// normalize-stderr-test "failed to write bytecode to /does-not-exist/output.non_ice_error_on_worker_io_fail.*" -> "io error modifying /does-not-exist/"
+
+// On Linux, we get an error like the below
+// normalize-stderr-test "couldn't create a temp dir.*" -> "io error modifying /does-not-exist/"
+
+// ignore-windows - this is a unix-specific test
+// ignore-emscripten - the file-system issues do not replicate here
+// ignore-wasm - the file-system issues do not replicate here
+// ignore-arm - the file-system issues do not replicate here, at least on armhf-gnu
+
+#![crate_type = "lib"]
+#![cfg_attr(not(feature = "std"), no_std)]
+pub mod task {
+    pub mod __internal {
+        use crate::task::Waker;
+    }
+    pub use core::task::Waker;
+}
diff --git a/tests/ui/io-checks/inaccessbile-temp-dir.stderr b/tests/ui/io-checks/inaccessbile-temp-dir.stderr
new file mode 100644 (file)
index 0000000..2fc5f93
--- /dev/null
@@ -0,0 +1,4 @@
+error: failed to find or create the directory specified by `--temps-dir`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/io-checks/non-ice-error-on-worker-io-fail.rs b/tests/ui/io-checks/non-ice-error-on-worker-io-fail.rs
new file mode 100644 (file)
index 0000000..134e7d4
--- /dev/null
@@ -0,0 +1,40 @@
+// Issue #66530: We would ICE if someone compiled with `-o /dev/null`,
+// because we would try to generate auxiliary files in `/dev/` (which
+// at least the OS X file system rejects).
+//
+// An attempt to `-o` into a directory we cannot write into should indeed
+// be an error; but not an ICE.
+//
+// However, some folks run tests as root, which can write `/dev/` and end
+// up clobbering `/dev/null`. Instead we'll use a non-existent path, which
+// also used to ICE, but even root can't magically write there.
+
+// compile-flags: -o /does-not-exist/output
+
+// The error-pattern check occurs *before* normalization, and the error patterns
+// are wildly different between build environments. So this is a cop-out (and we
+// rely on the checking of the normalized stderr output as our actual
+// "verification" of the diagnostic).
+
+// error-pattern: error
+
+// On Mac OS X, we get an error like the below
+// normalize-stderr-test "failed to write bytecode to /does-not-exist/output.non_ice_error_on_worker_io_fail.*" -> "io error modifying /does-not-exist/"
+
+// On Linux, we get an error like the below
+// normalize-stderr-test "couldn't create a temp dir.*" -> "io error modifying /does-not-exist/"
+
+// ignore-windows - this is a unix-specific test
+// ignore-emscripten - the file-system issues do not replicate here
+// ignore-wasm - the file-system issues do not replicate here
+// ignore-arm - the file-system issues do not replicate here, at least on armhf-gnu
+
+#![crate_type="lib"]
+
+#![cfg_attr(not(feature = "std"), no_std)]
+pub mod task {
+    pub mod __internal {
+        use crate::task::Waker;
+    }
+    pub use core::task::Waker;
+}
diff --git a/tests/ui/io-checks/non-ice-error-on-worker-io-fail.stderr b/tests/ui/io-checks/non-ice-error-on-worker-io-fail.stderr
new file mode 100644 (file)
index 0000000..edadecf
--- /dev/null
@@ -0,0 +1,6 @@
+warning: ignoring --out-dir flag due to -o flag
+
+error: io error modifying /does-not-exist/
+
+error: aborting due to previous error; 1 warning emitted
+
index 90f858f80e6b5ffe340dcf0aa222b962d56b32e1..ad97f7a4a7540d08bc99643e5bb17f99d721d37b 100644 (file)
@@ -25,8 +25,8 @@ fn arbitrary_consuming_method_for_demonstration_purposes() {
 
 
                 {
-                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem as usize\nWith captures:\n  elem = ",
-                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                    ::std::rt::panic_fmt(format_args!("Assertion failed: elem as usize\nWith captures:\n  elem = {0:?}\n",
+                            __capture0))
                 }
             }
     };
@@ -41,8 +41,8 @@ fn addr_of() {
         if ::core::intrinsics::unlikely(!&*__local_bind0) {
                 (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
                 {
-                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: &elem\nWith captures:\n  elem = ",
-                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                    ::std::rt::panic_fmt(format_args!("Assertion failed: &elem\nWith captures:\n  elem = {0:?}\n",
+                            __capture0))
                 }
             }
     };
@@ -57,8 +57,8 @@ fn binary() {
         if ::core::intrinsics::unlikely(!(*__local_bind0 == 1)) {
                 (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
                 {
-                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem == 1\nWith captures:\n  elem = ",
-                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                    ::std::rt::panic_fmt(format_args!("Assertion failed: elem == 1\nWith captures:\n  elem = {0:?}\n",
+                            __capture0))
                 }
             }
     };
@@ -70,8 +70,8 @@ fn binary() {
         if ::core::intrinsics::unlikely(!(*__local_bind0 >= 1)) {
                 (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
                 {
-                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem >= 1\nWith captures:\n  elem = ",
-                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                    ::std::rt::panic_fmt(format_args!("Assertion failed: elem >= 1\nWith captures:\n  elem = {0:?}\n",
+                            __capture0))
                 }
             }
     };
@@ -83,8 +83,8 @@ fn binary() {
         if ::core::intrinsics::unlikely(!(*__local_bind0 > 0)) {
                 (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
                 {
-                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem > 0\nWith captures:\n  elem = ",
-                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                    ::std::rt::panic_fmt(format_args!("Assertion failed: elem > 0\nWith captures:\n  elem = {0:?}\n",
+                            __capture0))
                 }
             }
     };
@@ -96,8 +96,8 @@ fn binary() {
         if ::core::intrinsics::unlikely(!(*__local_bind0 < 3)) {
                 (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
                 {
-                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem < 3\nWith captures:\n  elem = ",
-                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                    ::std::rt::panic_fmt(format_args!("Assertion failed: elem < 3\nWith captures:\n  elem = {0:?}\n",
+                            __capture0))
                 }
             }
     };
@@ -109,8 +109,8 @@ fn binary() {
         if ::core::intrinsics::unlikely(!(*__local_bind0 <= 3)) {
                 (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
                 {
-                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem <= 3\nWith captures:\n  elem = ",
-                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                    ::std::rt::panic_fmt(format_args!("Assertion failed: elem <= 3\nWith captures:\n  elem = {0:?}\n",
+                            __capture0))
                 }
             }
     };
@@ -122,8 +122,8 @@ fn binary() {
         if ::core::intrinsics::unlikely(!(*__local_bind0 != 3)) {
                 (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
                 {
-                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: elem != 3\nWith captures:\n  elem = ",
-                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                    ::std::rt::panic_fmt(format_args!("Assertion failed: elem != 3\nWith captures:\n  elem = {0:?}\n",
+                            __capture0))
                 }
             }
     };
@@ -138,8 +138,8 @@ fn unary() {
         if ::core::intrinsics::unlikely(!**__local_bind0) {
                 (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0);
                 {
-                    ::std::rt::panic_fmt(::core::fmt::Arguments::new_v1(&["Assertion failed: *elem\nWith captures:\n  elem = ",
-                                        "\n"], &[::core::fmt::ArgumentV1::new_debug(&__capture0)]))
+                    ::std::rt::panic_fmt(format_args!("Assertion failed: *elem\nWith captures:\n  elem = {0:?}\n",
+                            __capture0))
                 }
             }
     };
diff --git a/tests/ui/non-ice-error-on-worker-io-fail.rs b/tests/ui/non-ice-error-on-worker-io-fail.rs
deleted file mode 100644 (file)
index 134e7d4..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-// Issue #66530: We would ICE if someone compiled with `-o /dev/null`,
-// because we would try to generate auxiliary files in `/dev/` (which
-// at least the OS X file system rejects).
-//
-// An attempt to `-o` into a directory we cannot write into should indeed
-// be an error; but not an ICE.
-//
-// However, some folks run tests as root, which can write `/dev/` and end
-// up clobbering `/dev/null`. Instead we'll use a non-existent path, which
-// also used to ICE, but even root can't magically write there.
-
-// compile-flags: -o /does-not-exist/output
-
-// The error-pattern check occurs *before* normalization, and the error patterns
-// are wildly different between build environments. So this is a cop-out (and we
-// rely on the checking of the normalized stderr output as our actual
-// "verification" of the diagnostic).
-
-// error-pattern: error
-
-// On Mac OS X, we get an error like the below
-// normalize-stderr-test "failed to write bytecode to /does-not-exist/output.non_ice_error_on_worker_io_fail.*" -> "io error modifying /does-not-exist/"
-
-// On Linux, we get an error like the below
-// normalize-stderr-test "couldn't create a temp dir.*" -> "io error modifying /does-not-exist/"
-
-// ignore-windows - this is a unix-specific test
-// ignore-emscripten - the file-system issues do not replicate here
-// ignore-wasm - the file-system issues do not replicate here
-// ignore-arm - the file-system issues do not replicate here, at least on armhf-gnu
-
-#![crate_type="lib"]
-
-#![cfg_attr(not(feature = "std"), no_std)]
-pub mod task {
-    pub mod __internal {
-        use crate::task::Waker;
-    }
-    pub use core::task::Waker;
-}
diff --git a/tests/ui/non-ice-error-on-worker-io-fail.stderr b/tests/ui/non-ice-error-on-worker-io-fail.stderr
deleted file mode 100644 (file)
index edadecf..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-warning: ignoring --out-dir flag due to -o flag
-
-error: io error modifying /does-not-exist/
-
-error: aborting due to previous error; 1 warning emitted
-
diff --git a/tests/ui/parser/anon-enums.rs b/tests/ui/parser/anon-enums.rs
new file mode 100644 (file)
index 0000000..56b8a3d
--- /dev/null
@@ -0,0 +1,17 @@
+fn foo(x: bool | i32) -> i32 | f64 {
+//~^ ERROR anonymous enums are not supported
+//~| ERROR anonymous enums are not supported
+    match x {
+        x: i32 => x, //~ ERROR expected
+        true => 42.,
+        false => 0.333,
+    }
+}
+
+fn main() {
+    match foo(true) {
+        42: i32 => (), //~ ERROR expected
+        _: f64 => (), //~ ERROR expected
+        x: i32 => (), //~ ERROR expected
+    }
+}
diff --git a/tests/ui/parser/anon-enums.stderr b/tests/ui/parser/anon-enums.stderr
new file mode 100644 (file)
index 0000000..8415822
--- /dev/null
@@ -0,0 +1,68 @@
+error: anonymous enums are not supported
+  --> $DIR/anon-enums.rs:1:16
+   |
+LL | fn foo(x: bool | i32) -> i32 | f64 {
+   |           ---- ^ ---
+   |
+   = help: create a named `enum` and use it here instead:
+           enum Name {
+               Variant1(bool),
+               Variant2(i32),
+           }
+
+error: anonymous enums are not supported
+  --> $DIR/anon-enums.rs:1:30
+   |
+LL | fn foo(x: bool | i32) -> i32 | f64 {
+   |                          --- ^ ---
+   |
+   = help: create a named `enum` and use it here instead:
+           enum Name {
+               Variant1(i32),
+               Variant2(f64),
+           }
+
+error: expected one of `@` or `|`, found `:`
+  --> $DIR/anon-enums.rs:5:10
+   |
+LL |         x: i32 => x,
+   |          ^ --- specifying the type of a pattern isn't supported
+   |          |
+   |          expected one of `@` or `|`
+   |
+help: maybe write a path separator here
+   |
+LL |         x::i32 => x,
+   |          ~~
+
+error: expected one of `...`, `..=`, `..`, or `|`, found `:`
+  --> $DIR/anon-enums.rs:13:11
+   |
+LL |         42: i32 => (),
+   |           ^ --- specifying the type of a pattern isn't supported
+   |           |
+   |           expected one of `...`, `..=`, `..`, or `|`
+
+error: expected `|`, found `:`
+  --> $DIR/anon-enums.rs:14:10
+   |
+LL |         _: f64 => (),
+   |          ^ --- specifying the type of a pattern isn't supported
+   |          |
+   |          expected `|`
+
+error: expected one of `@` or `|`, found `:`
+  --> $DIR/anon-enums.rs:15:10
+   |
+LL |         x: i32 => (),
+   |          ^ --- specifying the type of a pattern isn't supported
+   |          |
+   |          expected one of `@` or `|`
+   |
+help: maybe write a path separator here
+   |
+LL |         x::i32 => (),
+   |          ~~
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/parser/fake-anon-enums-in-macros.rs b/tests/ui/parser/fake-anon-enums-in-macros.rs
new file mode 100644 (file)
index 0000000..38fe8de
--- /dev/null
@@ -0,0 +1,20 @@
+// build-pass
+macro_rules! check_ty {
+    ($Z:ty) => { compile_error!("triggered"); };
+    ($X:ty | $Y:ty) => { $X };
+}
+
+macro_rules! check {
+    ($Z:ty) => { compile_error!("triggered"); };
+    ($X:ty | $Y:ty) => { };
+}
+
+check! { i32 | u8 }
+
+fn foo(x: check_ty! { i32 | u8 }) -> check_ty! { i32 | u8 } {
+    x
+}
+fn main() {
+    let x: check_ty! { i32 | u8 } = 42;
+    let _: check_ty! { i32 | u8 } = foo(x);
+}
index 0b7b67496d6f32df39107feb43e1c957a029ae21..e1ea38f2795df698983f335bbf6b77f13d29dad1 100644 (file)
@@ -68,7 +68,6 @@ fn main() {
         Foo:Bar::Baz => {}
         //~^ ERROR: expected one of
         //~| HELP: maybe write a path separator here
-        //~| ERROR: failed to resolve: `Bar` is a variant, not a module
     }
     match myfoo {
         Foo::Bar => {}
index 2050a16beb34983c63e96f847a82c1d23f3f16d5..63b072ac4cdc68c6c4f9ec8734f49945c45de38e 100644 (file)
@@ -2,89 +2,118 @@ error: expected one of `@` or `|`, found `:`
   --> $DIR/issue-87086-colon-path-sep.rs:17:12
    |
 LL |         Foo:Bar => {}
-   |            ^
+   |            ^--- specifying the type of a pattern isn't supported
    |            |
    |            expected one of `@` or `|`
-   |            help: maybe write a path separator here: `::`
+   |
+help: maybe write a path separator here
+   |
+LL |         Foo::Bar => {}
+   |            ~~
 
 error: expected one of `!`, `(`, `...`, `..=`, `..`, `::`, `{`, or `|`, found `:`
   --> $DIR/issue-87086-colon-path-sep.rs:23:17
    |
 LL |         qux::Foo:Bar => {}
-   |                 ^
+   |                 ^--- specifying the type of a pattern isn't supported
    |                 |
    |                 expected one of 8 possible tokens
-   |                 help: maybe write a path separator here: `::`
+   |
+help: maybe write a path separator here
+   |
+LL |         qux::Foo::Bar => {}
+   |                 ~~
 
 error: expected one of `@` or `|`, found `:`
   --> $DIR/issue-87086-colon-path-sep.rs:29:12
    |
 LL |         qux:Foo::Baz => {}
-   |            ^
+   |            ^-------- specifying the type of a pattern isn't supported
    |            |
    |            expected one of `@` or `|`
-   |            help: maybe write a path separator here: `::`
+   |
+help: maybe write a path separator here
+   |
+LL |         qux::Foo::Baz => {}
+   |            ~~
 
 error: expected one of `@` or `|`, found `:`
   --> $DIR/issue-87086-colon-path-sep.rs:35:12
    |
 LL |         qux: Foo::Baz if true => {}
-   |            ^
+   |            ^ -------- specifying the type of a pattern isn't supported
    |            |
    |            expected one of `@` or `|`
-   |            help: maybe write a path separator here: `::`
+   |
+help: maybe write a path separator here
+   |
+LL |         qux::Foo::Baz if true => {}
+   |            ~~
 
 error: expected one of `@` or `|`, found `:`
   --> $DIR/issue-87086-colon-path-sep.rs:40:15
    |
 LL |     if let Foo:Bar = f() {
-   |               ^
+   |               ^--- specifying the type of a pattern isn't supported
    |               |
    |               expected one of `@` or `|`
-   |               help: maybe write a path separator here: `::`
+   |
+help: maybe write a path separator here
+   |
+LL |     if let Foo::Bar = f() {
+   |               ~~
 
 error: expected one of `@` or `|`, found `:`
   --> $DIR/issue-87086-colon-path-sep.rs:48:16
    |
 LL |         ref qux: Foo::Baz => {}
-   |                ^
+   |                ^ -------- specifying the type of a pattern isn't supported
    |                |
    |                expected one of `@` or `|`
-   |                help: maybe write a path separator here: `::`
+   |
+help: maybe write a path separator here
+   |
+LL |         ref qux::Foo::Baz => {}
+   |                ~~
 
 error: expected one of `@` or `|`, found `:`
   --> $DIR/issue-87086-colon-path-sep.rs:57:16
    |
 LL |         mut qux: Foo::Baz => {}
-   |                ^
+   |                ^ -------- specifying the type of a pattern isn't supported
    |                |
    |                expected one of `@` or `|`
-   |                help: maybe write a path separator here: `::`
+   |
+help: maybe write a path separator here
+   |
+LL |         mut qux::Foo::Baz => {}
+   |                ~~
 
 error: expected one of `@` or `|`, found `:`
   --> $DIR/issue-87086-colon-path-sep.rs:68:12
    |
 LL |         Foo:Bar::Baz => {}
-   |            ^
+   |            ^-------- specifying the type of a pattern isn't supported
    |            |
    |            expected one of `@` or `|`
-   |            help: maybe write a path separator here: `::`
+   |
+help: maybe write a path separator here
+   |
+LL |         Foo::Bar::Baz => {}
+   |            ~~
 
 error: expected one of `@` or `|`, found `:`
-  --> $DIR/issue-87086-colon-path-sep.rs:75:12
+  --> $DIR/issue-87086-colon-path-sep.rs:74:12
    |
 LL |         Foo:Bar => {}
-   |            ^
+   |            ^--- specifying the type of a pattern isn't supported
    |            |
    |            expected one of `@` or `|`
-   |            help: maybe write a path separator here: `::`
-
-error[E0433]: failed to resolve: `Bar` is a variant, not a module
-  --> $DIR/issue-87086-colon-path-sep.rs:68:13
    |
-LL |         Foo:Bar::Baz => {}
-   |             ^^^ `Bar` is a variant, not a module
+help: maybe write a path separator here
+   |
+LL |         Foo::Bar => {}
+   |            ~~
 
-error: aborting due to 10 previous errors
+error: aborting due to 9 previous errors
 
-For more information about this error, try `rustc --explain E0433`.
index c8b45fd24d98c00c916c3b7b292ecf6be0d7c480..29cd6c45c34b58410d02148ea7ca9b83754a7ae4 100644 (file)
@@ -4,8 +4,8 @@ error: cannot move out of value because it is borrowed
 LL |         Some(ref _y @ _z) => {}
    |              ------^^^--
    |              |        |
-   |              |        value moved into `_z` here
-   |              value borrowed, by `_y`, here
+   |              |        value is moved into `_z` here
+   |              value is borrowed by `_y` here
 
 error: borrow of moved value
   --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:19:14
@@ -28,8 +28,8 @@ error: cannot move out of value because it is borrowed
 LL |         Some(ref mut _y @ _z) => {}
    |              ----------^^^--
    |              |            |
-   |              |            value moved into `_z` here
-   |              value borrowed, by `_y`, here
+   |              |            value is moved into `_z` here
+   |              value is mutably borrowed by `_y` here
 
 error: borrow of moved value
   --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:33:14
index f27df32ccfa5ce2afbe63b73b2f62255371b7228..2c123b01e173e7c12f5217aebd80ef72001692f2 100644 (file)
@@ -4,8 +4,8 @@ error: cannot move out of value because it is borrowed
 LL |     let ref a @ box b = Box::new(NC);
    |         -----^^^^^^^-
    |         |           |
-   |         |           value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |           value is moved into `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-at-and-box.rs:34:9
@@ -13,8 +13,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref a @ box ref mut b = Box::new(nc());
    |         -----^^^^^^^---------
    |         |           |
-   |         |           mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |           value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-at-and-box.rs:36:9
@@ -22,8 +22,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref a @ box ref mut b = Box::new(NC);
    |         -----^^^^^^^---------
    |         |           |
-   |         |           mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |           value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-at-and-box.rs:38:9
@@ -31,8 +31,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref a @ box ref mut b = Box::new(NC);
    |         -----^^^^^^^---------
    |         |           |
-   |         |           mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |           value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-at-and-box.rs:42:9
@@ -40,8 +40,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref a @ box ref mut b = Box::new(NC);
    |         -----^^^^^^^---------
    |         |           |
-   |         |           mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |           value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-at-and-box.rs:48:9
@@ -49,8 +49,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |     let ref mut a @ box ref b = Box::new(NC);
    |         ---------^^^^^^^-----
    |         |               |
-   |         |               immutable borrow, by `b`, occurs here
-   |         mutable borrow, by `a`, occurs here
+   |         |               value is borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-at-and-box.rs:62:9
@@ -58,8 +58,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |         ref mut a @ box ref b => {
    |         ---------^^^^^^^-----
    |         |               |
-   |         |               immutable borrow, by `b`, occurs here
-   |         mutable borrow, by `a`, occurs here
+   |         |               value is borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-at-and-box.rs:54:11
@@ -67,8 +67,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |     fn f5(ref mut a @ box ref b: Box<NC>) {
    |           ---------^^^^^^^-----
    |           |               |
-   |           |               immutable borrow, by `b`, occurs here
-   |           mutable borrow, by `a`, occurs here
+   |           |               value is borrowed by `b` here
+   |           value is mutably borrowed by `a` here
 
 error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-at-and-box.rs:31:9
index 770bb89530ccaa60c2a1b63605854ca5f76e29f9..4f7fbc9e04b04591f7f3bf967ef57fbd64ffa8ec 100644 (file)
@@ -4,8 +4,8 @@ error: cannot move out of value because it is borrowed
 LL |     let ref a @ b = U;
    |         -----^^^-
    |         |       |
-   |         |       value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |       value is moved into `b` here
+   |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:26:9
@@ -13,9 +13,9 @@ error: cannot move out of value because it is borrowed
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
    |         -----^^^^^^^^^^^^-----^^^^^^^^^^-^
    |         |                |              |
-   |         |                |              value moved into `e` here
-   |         |                value moved into `c` here
-   |         value borrowed, by `a`, here
+   |         |                |              value is moved into `e` here
+   |         |                value is moved into `c` here
+   |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:26:18
@@ -23,8 +23,8 @@ error: cannot move out of value because it is borrowed
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
    |                  -----^^^-----
    |                  |       |
-   |                  |       value moved into `c` here
-   |                  value borrowed, by `b`, here
+   |                  |       value is moved into `c` here
+   |                  value is borrowed by `b` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:26:33
@@ -32,8 +32,8 @@ error: cannot move out of value because it is borrowed
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
    |                                 -----^^^-
    |                                 |       |
-   |                                 |       value moved into `e` here
-   |                                 value borrowed, by `d`, here
+   |                                 |       value is moved into `e` here
+   |                                 value is borrowed by `d` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9
@@ -41,9 +41,9 @@ error: cannot move out of value because it is borrowed
 LL |     let ref mut a @ [b, mut c] = [U, U];
    |         ---------^^^^-^^-----^
    |         |            |  |
-   |         |            |  value moved into `c` here
-   |         |            value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |            |  value is moved into `c` here
+   |         |            value is moved into `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9
@@ -51,8 +51,8 @@ error: cannot move out of value because it is borrowed
 LL |     let ref a @ b = u();
    |         -----^^^-
    |         |       |
-   |         |       value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |       value is moved into `b` here
+   |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:36:9
@@ -60,9 +60,9 @@ error: cannot move out of value because it is borrowed
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
    |         -----^^^^^^^^^^^^-----^^^^^^^^^^-^
    |         |                |              |
-   |         |                |              value moved into `e` here
-   |         |                value moved into `c` here
-   |         value borrowed, by `a`, here
+   |         |                |              value is moved into `e` here
+   |         |                value is moved into `c` here
+   |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:36:18
@@ -70,8 +70,8 @@ error: cannot move out of value because it is borrowed
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
    |                  -----^^^-----
    |                  |       |
-   |                  |       value moved into `c` here
-   |                  value borrowed, by `b`, here
+   |                  |       value is moved into `c` here
+   |                  value is borrowed by `b` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:36:33
@@ -79,8 +79,8 @@ error: cannot move out of value because it is borrowed
 LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
    |                                 -----^^^-
    |                                 |       |
-   |                                 |       value moved into `e` here
-   |                                 value borrowed, by `d`, here
+   |                                 |       value is moved into `e` here
+   |                                 value is borrowed by `d` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:42:9
@@ -88,9 +88,9 @@ error: cannot move out of value because it is borrowed
 LL |     let ref mut a @ [b, mut c] = [u(), u()];
    |         ---------^^^^-^^-----^
    |         |            |  |
-   |         |            |  value moved into `c` here
-   |         |            value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |            |  value is moved into `c` here
+   |         |            value is moved into `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:47:9
@@ -98,8 +98,8 @@ error: cannot move out of value because it is borrowed
 LL |         ref a @ Some(b) => {}
    |         -----^^^^^^^^-^
    |         |            |
-   |         |            value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |            value is moved into `b` here
+   |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:52:9
@@ -107,9 +107,9 @@ error: cannot move out of value because it is borrowed
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |         -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^
    |         |                     |              |
-   |         |                     |              value moved into `e` here
-   |         |                     value moved into `c` here
-   |         value borrowed, by `a`, here
+   |         |                     |              value is moved into `e` here
+   |         |                     value is moved into `c` here
+   |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:52:23
@@ -117,8 +117,8 @@ error: cannot move out of value because it is borrowed
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                       -----^^^-----
    |                       |       |
-   |                       |       value moved into `c` here
-   |                       value borrowed, by `b`, here
+   |                       |       value is moved into `c` here
+   |                       value is borrowed by `b` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:52:38
@@ -126,8 +126,8 @@ error: cannot move out of value because it is borrowed
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                                      -----^^^-
    |                                      |       |
-   |                                      |       value moved into `e` here
-   |                                      value borrowed, by `d`, here
+   |                                      |       value is moved into `e` here
+   |                                      value is borrowed by `d` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:59:9
@@ -135,9 +135,9 @@ error: cannot move out of value because it is borrowed
 LL |         ref mut a @ Some([b, mut c]) => {}
    |         ---------^^^^^^^^^-^^-----^^
    |         |                 |  |
-   |         |                 |  value moved into `c` here
-   |         |                 value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |                 |  value is moved into `c` here
+   |         |                 value is moved into `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:64:9
@@ -145,8 +145,8 @@ error: cannot move out of value because it is borrowed
 LL |         ref a @ Some(b) => {}
    |         -----^^^^^^^^-^
    |         |            |
-   |         |            value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |            value is moved into `b` here
+   |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:69:9
@@ -154,9 +154,9 @@ error: cannot move out of value because it is borrowed
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |         -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^
    |         |                     |              |
-   |         |                     |              value moved into `e` here
-   |         |                     value moved into `c` here
-   |         value borrowed, by `a`, here
+   |         |                     |              value is moved into `e` here
+   |         |                     value is moved into `c` here
+   |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:69:23
@@ -164,8 +164,8 @@ error: cannot move out of value because it is borrowed
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                       -----^^^-----
    |                       |       |
-   |                       |       value moved into `c` here
-   |                       value borrowed, by `b`, here
+   |                       |       value is moved into `c` here
+   |                       value is borrowed by `b` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:69:38
@@ -173,8 +173,8 @@ error: cannot move out of value because it is borrowed
 LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                                      -----^^^-
    |                                      |       |
-   |                                      |       value moved into `e` here
-   |                                      value borrowed, by `d`, here
+   |                                      |       value is moved into `e` here
+   |                                      value is borrowed by `d` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:78:9
@@ -182,9 +182,9 @@ error: cannot move out of value because it is borrowed
 LL |         ref mut a @ Some([b, mut c]) => {}
    |         ---------^^^^^^^^^-^^-----^^
    |         |                 |  |
-   |         |                 |  value moved into `c` here
-   |         |                 value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |                 |  value is moved into `c` here
+   |         |                 value is moved into `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:11:11
@@ -192,8 +192,8 @@ error: cannot move out of value because it is borrowed
 LL |     fn f1(ref a @ b: U) {}
    |           -----^^^-
    |           |       |
-   |           |       value moved into `b` here
-   |           value borrowed, by `a`, here
+   |           |       value is moved into `b` here
+   |           value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:14:11
@@ -201,9 +201,9 @@ error: cannot move out of value because it is borrowed
 LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
    |           -----^^^^^^^^^^^^-----^^^^^^^^^^-^
    |           |                |              |
-   |           |                |              value moved into `e` here
-   |           |                value moved into `c` here
-   |           value borrowed, by `a`, here
+   |           |                |              value is moved into `e` here
+   |           |                value is moved into `c` here
+   |           value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:14:20
@@ -211,8 +211,8 @@ error: cannot move out of value because it is borrowed
 LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
    |                    -----^^^-----
    |                    |       |
-   |                    |       value moved into `c` here
-   |                    value borrowed, by `b`, here
+   |                    |       value is moved into `c` here
+   |                    value is borrowed by `b` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:14:35
@@ -220,8 +220,8 @@ error: cannot move out of value because it is borrowed
 LL |     fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
    |                                   -----^^^-
    |                                   |       |
-   |                                   |       value moved into `e` here
-   |                                   value borrowed, by `d`, here
+   |                                   |       value is moved into `e` here
+   |                                   value is borrowed by `d` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-by-move-and-ref.rs:20:11
@@ -229,9 +229,9 @@ error: cannot move out of value because it is borrowed
 LL |     fn f3(ref mut a @ [b, mut c]: [U; 2]) {}
    |           ---------^^^^-^^-----^
    |           |            |  |
-   |           |            |  value moved into `c` here
-   |           |            value moved into `b` here
-   |           value borrowed, by `a`, here
+   |           |            |  value is moved into `c` here
+   |           |            value is moved into `b` here
+   |           value is mutably borrowed by `a` here
 
 error[E0382]: borrow of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9
index 8546b4bb477349d7b29391a5e64824efc6e20e07..f51b5041858c6ac43f01a7811839e925e8119791 100644 (file)
@@ -4,8 +4,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |         ref mut z @ &mut Some(ref a) => {
    |         ---------^^^^^^^^^^^^^-----^
    |         |                     |
-   |         |                     immutable borrow, by `a`, occurs here
-   |         mutable borrow, by `z`, occurs here
+   |         |                     value is borrowed by `a` here
+   |         value is mutably borrowed by `z` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:33:9
@@ -13,9 +13,9 @@ error: cannot borrow value as mutable more than once at a time
 LL |     let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub
    |         ---------^^^^-----------------^
    |         |            |       |
-   |         |            |       another mutable borrow, by `c`, occurs here
-   |         |            also borrowed as immutable, by `b`, here
-   |         first mutable borrow, by `a`, occurs here
+   |         |            |       value is mutably borrowed by `c` here
+   |         |            value is borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:33:22
@@ -23,8 +23,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub
    |                      -----^^^---------
    |                      |       |
-   |                      |       mutable borrow, by `c`, occurs here
-   |                      immutable borrow, by `b`, occurs here
+   |                      |       value is mutably borrowed by `c` here
+   |                      value is borrowed by `b` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:37:9
@@ -32,8 +32,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref a @ ref mut b = U;
    |         -----^^^---------
    |         |       |
-   |         |       mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |       value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:39:9
@@ -41,8 +41,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |     let ref mut a @ ref b = U;
    |         ---------^^^-----
    |         |           |
-   |         |           immutable borrow, by `b`, occurs here
-   |         mutable borrow, by `a`, occurs here
+   |         |           value is borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:41:9
@@ -50,9 +50,9 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         -----^^^^---------^^---------^
    |         |        |          |
-   |         |        |          mutable borrow, by `c`, occurs here
-   |         |        mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |        |          value is mutably borrowed by `c` here
+   |         |        value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:43:9
@@ -60,9 +60,9 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |     let ref mut a @ (ref b, ref c) = (U, U);
    |         ---------^^^^-----^^-----^
    |         |            |      |
-   |         |            |      immutable borrow, by `c`, occurs here
-   |         |            immutable borrow, by `b`, occurs here
-   |         mutable borrow, by `a`, occurs here
+   |         |            |      value is borrowed by `c` here
+   |         |            value is borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:46:9
@@ -70,8 +70,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |     let ref mut a @ ref b = u();
    |         ---------^^^-----
    |         |           |
-   |         |           immutable borrow, by `b`, occurs here
-   |         mutable borrow, by `a`, occurs here
+   |         |           value is borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:51:9
@@ -79,8 +79,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref a @ ref mut b = u();
    |         -----^^^---------
    |         |       |
-   |         |       mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |       value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:57:9
@@ -88,8 +88,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |     let ref mut a @ ref b = U;
    |         ---------^^^-----
    |         |           |
-   |         |           immutable borrow, by `b`, occurs here
-   |         mutable borrow, by `a`, occurs here
+   |         |           value is borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:61:9
@@ -97,8 +97,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref a @ ref mut b = U;
    |         -----^^^---------
    |         |       |
-   |         |       mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |       value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:67:9
@@ -106,8 +106,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => {
    |         ---------^^^^^^-----^
    |         |              |
-   |         |              immutable borrow, by `b`, occurs here
-   |         mutable borrow, by `a`, occurs here
+   |         |              value is borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:67:33
@@ -115,8 +115,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => {
    |                                 ---------^^^^^^^-----^
    |                                 |               |
-   |                                 |               immutable borrow, by `b`, occurs here
-   |                                 mutable borrow, by `a`, occurs here
+   |                                 |               value is borrowed by `b` here
+   |                                 value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:9
@@ -124,8 +124,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
    |         -----^^^^^^---------^
    |         |          |
-   |         |          mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |          value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:33
@@ -133,8 +133,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
    |                                 -----^^^^^^^---------^
    |                                 |           |
-   |                                 |           mutable borrow, by `b`, occurs here
-   |                                 immutable borrow, by `a`, occurs here
+   |                                 |           value is mutably borrowed by `b` here
+   |                                 value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:9
@@ -142,8 +142,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
    |         -----^^^^^^---------^
    |         |          |
-   |         |          mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |          value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:33
@@ -151,8 +151,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
    |                                 -----^^^^^^^---------^
    |                                 |           |
-   |                                 |           mutable borrow, by `b`, occurs here
-   |                                 immutable borrow, by `a`, occurs here
+   |                                 |           value is mutably borrowed by `b` here
+   |                                 value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:9
@@ -160,8 +160,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
    |         ---------^^^^^^-----^
    |         |              |
-   |         |              immutable borrow, by `b`, occurs here
-   |         mutable borrow, by `a`, occurs here
+   |         |              value is borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:33
@@ -169,8 +169,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
    |                                 ---------^^^^^^^-----^
    |                                 |               |
-   |                                 |               immutable borrow, by `b`, occurs here
-   |                                 mutable borrow, by `a`, occurs here
+   |                                 |               value is borrowed by `b` here
+   |                                 value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:9
@@ -178,8 +178,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
    |         -----^^^^^^---------^
    |         |          |
-   |         |          mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |          value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:33
@@ -187,8 +187,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |         ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
    |                                 -----^^^^^^^---------^
    |                                 |           |
-   |                                 |           mutable borrow, by `b`, occurs here
-   |                                 immutable borrow, by `a`, occurs here
+   |                                 |           value is mutably borrowed by `b` here
+   |                                 value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:9
@@ -196,8 +196,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
    |         ---------^^^^^^-----^
    |         |              |
-   |         |              immutable borrow, by `b`, occurs here
-   |         mutable borrow, by `a`, occurs here
+   |         |              value is borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:33
@@ -205,8 +205,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |         ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
    |                                 ---------^^^^^^^-----^
    |                                 |               |
-   |                                 |               immutable borrow, by `b`, occurs here
-   |                                 mutable borrow, by `a`, occurs here
+   |                                 |               value is borrowed by `b` here
+   |                                 value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:117:9
@@ -214,9 +214,9 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         -----^^^^---------^^---------^
    |         |        |          |
-   |         |        |          mutable borrow, by `c`, occurs here
-   |         |        mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |        |          value is mutably borrowed by `c` here
+   |         |        value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9
@@ -224,9 +224,9 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         -----^^^^---------^^---------^
    |         |        |          |
-   |         |        |          mutable borrow, by `c`, occurs here
-   |         |        mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |        |          value is mutably borrowed by `c` here
+   |         |        value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:129:9
@@ -234,9 +234,9 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
    |         -----^^^^---------^^---------^
    |         |        |          |
-   |         |        |          mutable borrow, by `c`, occurs here
-   |         |        mutable borrow, by `b`, occurs here
-   |         immutable borrow, by `a`, occurs here
+   |         |        |          value is mutably borrowed by `c` here
+   |         |        value is mutably borrowed by `b` here
+   |         value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:134:9
@@ -244,9 +244,9 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |     let ref mut a @ (ref b, ref c) = (U, U);
    |         ---------^^^^-----^^-----^
    |         |            |      |
-   |         |            |      immutable borrow, by `c`, occurs here
-   |         |            immutable borrow, by `b`, occurs here
-   |         mutable borrow, by `a`, occurs here
+   |         |            |      value is borrowed by `c` here
+   |         |            value is borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:22:11
@@ -254,8 +254,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     fn f1(ref a @ ref mut b: U) {}
    |           -----^^^---------
    |           |       |
-   |           |       mutable borrow, by `b`, occurs here
-   |           immutable borrow, by `a`, occurs here
+   |           |       value is mutably borrowed by `b` here
+   |           value is borrowed by `a` here
 
 error: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:24:11
@@ -263,8 +263,8 @@ error: cannot borrow value as immutable because it is also borrowed as mutable
 LL |     fn f2(ref mut a @ ref b: U) {}
    |           ---------^^^-----
    |           |           |
-   |           |           immutable borrow, by `b`, occurs here
-   |           mutable borrow, by `a`, occurs here
+   |           |           value is borrowed by `b` here
+   |           value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:26:11
@@ -272,8 +272,8 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {}
    |           -----^^^^^^^^^^^----------------^^^^^^^^
    |           |               |
-   |           |               mutable borrow, by `mid`, occurs here
-   |           immutable borrow, by `a`, occurs here
+   |           |               value is mutably borrowed by `mid` here
+   |           value is borrowed by `a` here
 
 error: cannot borrow value as mutable because it is also borrowed as immutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:22
@@ -281,9 +281,9 @@ error: cannot borrow value as mutable because it is also borrowed as immutable
 LL |     fn f4_also_moved(ref a @ ref mut b @ c: U) {}
    |                      -----^^^-------------
    |                      |       |           |
-   |                      |       |           also moved into `c` here
-   |                      |       mutable borrow, by `b`, occurs here
-   |                      immutable borrow, by `a`, occurs here
+   |                      |       |           value is moved into `c` here
+   |                      |       value is mutably borrowed by `b` here
+   |                      value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:30
@@ -291,8 +291,8 @@ error: cannot move out of value because it is borrowed
 LL |     fn f4_also_moved(ref a @ ref mut b @ c: U) {}
    |                              ---------^^^-
    |                              |           |
-   |                              |           value moved into `c` here
-   |                              value borrowed, by `b`, here
+   |                              |           value is moved into `c` here
+   |                              value is mutably borrowed by `b` here
 
 error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-ref-mut-and-ref.rs:8:31
index ad4ce7952ca7494b065b86b9f62107b24655d5ea..a0cb04a064e06dd05796771dedeafd28b6cea917 100644 (file)
@@ -4,8 +4,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |     let ref mut a @ ref mut b = U;
    |         ---------^^^---------
    |         |           |
-   |         |           another mutable borrow, by `b`, occurs here
-   |         first mutable borrow, by `a`, occurs here
+   |         |           value is mutably borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:29:9
@@ -13,8 +13,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |     let ref mut a @ ref mut b = U;
    |         ---------^^^---------
    |         |           |
-   |         |           another mutable borrow, by `b`, occurs here
-   |         first mutable borrow, by `a`, occurs here
+   |         |           value is mutably borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:33:9
@@ -22,8 +22,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |     let ref mut a @ ref mut b = U;
    |         ---------^^^---------
    |         |           |
-   |         |           another mutable borrow, by `b`, occurs here
-   |         first mutable borrow, by `a`, occurs here
+   |         |           value is mutably borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:36:9
@@ -31,8 +31,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |     let ref mut a @ ref mut b = U;
    |         ---------^^^---------
    |         |           |
-   |         |           another mutable borrow, by `b`, occurs here
-   |         first mutable borrow, by `a`, occurs here
+   |         |           value is mutably borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:39:9
@@ -40,8 +40,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |     let ref mut a @ ref mut b = U;
    |         ---------^^^---------
    |         |           |
-   |         |           another mutable borrow, by `b`, occurs here
-   |         first mutable borrow, by `a`, occurs here
+   |         |           value is mutably borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:44:9
@@ -49,18 +49,18 @@ error: cannot borrow value as mutable more than once at a time
 LL |       let ref mut a @ (
    |           ^--------
    |           |
-   |  _________first mutable borrow, by `a`, occurs here
+   |  _________value is mutably borrowed by `a` here
    | |
 LL | |
 LL | |         ref mut b,
-   | |         --------- another mutable borrow, by `b`, occurs here
+   | |         --------- value is mutably borrowed by `b` here
 LL | |         [
 LL | |             ref mut c,
-   | |             --------- another mutable borrow, by `c`, occurs here
+   | |             --------- value is mutably borrowed by `c` here
 LL | |             ref mut d,
-   | |             --------- another mutable borrow, by `d`, occurs here
+   | |             --------- value is mutably borrowed by `d` here
 LL | |             ref e,
-   | |             ----- also borrowed as immutable, by `e`, here
+   | |             ----- value is borrowed by `e` here
 LL | |         ]
 LL | |     ) = (U, [U, U, U]);
    | |_____^
@@ -71,18 +71,18 @@ error: cannot borrow value as mutable more than once at a time
 LL |       let ref mut a @ (
    |           ^--------
    |           |
-   |  _________first mutable borrow, by `a`, occurs here
+   |  _________value is mutably borrowed by `a` here
    | |
 LL | |
 LL | |             ref mut b,
-   | |             --------- another mutable borrow, by `b`, occurs here
+   | |             --------- value is mutably borrowed by `b` here
 LL | |             [
 LL | |                 ref mut c,
-   | |                 --------- another mutable borrow, by `c`, occurs here
+   | |                 --------- value is mutably borrowed by `c` here
 LL | |                 ref mut d,
-   | |                 --------- another mutable borrow, by `d`, occurs here
+   | |                 --------- value is mutably borrowed by `d` here
 LL | |                 ref e,
-   | |                 ----- also borrowed as immutable, by `e`, here
+   | |                 ----- value is borrowed by `e` here
 LL | |             ]
 LL | |         ) = (u(), [u(), u(), u()]);
    | |_________^
@@ -157,8 +157,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         ---------^^^^^^---------^
    |         |              |
-   |         |              another mutable borrow, by `b`, occurs here
-   |         first mutable borrow, by `a`, occurs here
+   |         |              value is mutably borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:76:37
@@ -166,8 +166,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     ---------^^^^^^^---------^
    |                                     |               |
-   |                                     |               another mutable borrow, by `b`, occurs here
-   |                                     first mutable borrow, by `a`, occurs here
+   |                                     |               value is mutably borrowed by `b` here
+   |                                     value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:82:9
@@ -175,8 +175,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         ---------^^^^^^---------^
    |         |              |
-   |         |              another mutable borrow, by `b`, occurs here
-   |         first mutable borrow, by `a`, occurs here
+   |         |              value is mutably borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:82:37
@@ -184,8 +184,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     ---------^^^^^^^---------^
    |                                     |               |
-   |                                     |               another mutable borrow, by `b`, occurs here
-   |                                     first mutable borrow, by `a`, occurs here
+   |                                     |               value is mutably borrowed by `b` here
+   |                                     value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:89:9
@@ -193,8 +193,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         ---------^^^^^^---------^
    |         |              |
-   |         |              another mutable borrow, by `b`, occurs here
-   |         first mutable borrow, by `a`, occurs here
+   |         |              value is mutably borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:89:37
@@ -202,8 +202,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     ---------^^^^^^^---------^
    |                                     |               |
-   |                                     |               another mutable borrow, by `b`, occurs here
-   |                                     first mutable borrow, by `a`, occurs here
+   |                                     |               value is mutably borrowed by `b` here
+   |                                     value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:101:9
@@ -211,8 +211,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |         ---------^^^^^^---------^
    |         |              |
-   |         |              another mutable borrow, by `b`, occurs here
-   |         first mutable borrow, by `a`, occurs here
+   |         |              value is mutably borrowed by `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:101:37
@@ -220,8 +220,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |         ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
    |                                     ---------^^^^^^^---------^
    |                                     |               |
-   |                                     |               another mutable borrow, by `b`, occurs here
-   |                                     first mutable borrow, by `a`, occurs here
+   |                                     |               value is mutably borrowed by `b` here
+   |                                     value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:8:11
@@ -229,8 +229,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |     fn f1(ref mut a @ ref mut b: U) {}
    |           ---------^^^---------
    |           |           |
-   |           |           another mutable borrow, by `b`, occurs here
-   |           first mutable borrow, by `a`, occurs here
+   |           |           value is mutably borrowed by `b` here
+   |           value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:10:11
@@ -238,8 +238,8 @@ error: cannot borrow value as mutable more than once at a time
 LL |     fn f2(ref mut a @ ref mut b: U) {}
    |           ---------^^^---------
    |           |           |
-   |           |           another mutable borrow, by `b`, occurs here
-   |           first mutable borrow, by `a`, occurs here
+   |           |           value is mutably borrowed by `b` here
+   |           value is mutably borrowed by `a` here
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:13:9
@@ -247,13 +247,13 @@ error: cannot borrow value as mutable more than once at a time
 LL |           ref mut a @ [
    |           ^--------
    |           |
-   |  _________first mutable borrow, by `a`, occurs here
+   |  _________value is mutably borrowed by `a` here
    | |
 LL | |
 LL | |             [ref b @ .., _],
-   | |              ---------- also borrowed as immutable, by `b`, here
+   | |              ---------- value is borrowed by `b` here
 LL | |             [_, ref mut mid @ ..],
-   | |                 ---------------- another mutable borrow, by `mid`, occurs here
+   | |                 ---------------- value is mutably borrowed by `mid` here
 LL | |             ..,
 LL | |             [..],
 LL | |         ] : [[U; 4]; 5]
@@ -265,9 +265,9 @@ error: cannot borrow value as mutable more than once at a time
 LL |     fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
    |                      ---------^^^-------------
    |                      |           |           |
-   |                      |           |           also moved into `c` here
-   |                      |           another mutable borrow, by `b`, occurs here
-   |                      first mutable borrow, by `a`, occurs here
+   |                      |           |           value is moved into `c` here
+   |                      |           value is mutably borrowed by `b` here
+   |                      value is mutably borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/borrowck-pat-ref-mut-twice.rs:21:34
@@ -275,8 +275,8 @@ error: cannot move out of value because it is borrowed
 LL |     fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
    |                                  ---------^^^-
    |                                  |           |
-   |                                  |           value moved into `c` here
-   |                                  value borrowed, by `b`, here
+   |                                  |           value is moved into `c` here
+   |                                  value is mutably borrowed by `b` here
 
 error[E0499]: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:29:9
index 638bdd6db7606761b035dfea6375a9b9761c5487..73ebbf48118daebf4cdd798f82374b856a949f5a 100644 (file)
@@ -4,8 +4,8 @@ error: cannot move out of value because it is borrowed
 LL |     let ref a @ b = NotCopy;
    |         -----^^^-
    |         |       |
-   |         |       value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |       value is moved into `b` here
+   |         value is borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/default-binding-modes-both-sides-independent.rs:29:9
@@ -13,8 +13,8 @@ error: cannot move out of value because it is borrowed
 LL |     let ref mut a @ b = NotCopy;
    |         ---------^^^-
    |         |           |
-   |         |           value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |           value is moved into `b` here
+   |         value is mutably borrowed by `a` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/default-binding-modes-both-sides-independent.rs:34:12
@@ -22,8 +22,8 @@ error: cannot move out of value because it is borrowed
 LL |         Ok(ref a @ b) | Err(b @ ref a) => {
    |            -----^^^-
    |            |       |
-   |            |       value moved into `b` here
-   |            value borrowed, by `a`, here
+   |            |       value is moved into `b` here
+   |            value is borrowed by `a` here
 
 error: borrow of moved value
   --> $DIR/default-binding-modes-both-sides-independent.rs:34:29
@@ -46,8 +46,8 @@ error: cannot move out of value because it is borrowed
 LL |         ref a @ b => {
    |         -----^^^-
    |         |       |
-   |         |       value moved into `b` here
-   |         value borrowed, by `a`, here
+   |         |       value is moved into `b` here
+   |         value is borrowed by `a` here
 
 error[E0382]: borrow of moved value
   --> $DIR/default-binding-modes-both-sides-independent.rs:29:9
diff --git a/tests/ui/proc-macro/allowed-signatures.rs b/tests/ui/proc-macro/allowed-signatures.rs
new file mode 100644 (file)
index 0000000..8685087
--- /dev/null
@@ -0,0 +1,26 @@
+// check-pass
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![allow(private_in_public)]
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn foo<T>(t: T) -> TokenStream {
+  TokenStream::new()
+}
+
+trait Project {
+    type Assoc;
+}
+
+impl Project for () {
+    type Assoc = TokenStream;
+}
+
+#[proc_macro]
+pub fn uwu(_input: <() as Project>::Assoc) -> <() as Project>::Assoc {
+    TokenStream::new()
+}
diff --git a/tests/ui/proc-macro/proc-macro-abi.rs b/tests/ui/proc-macro/proc-macro-abi.rs
new file mode 100644 (file)
index 0000000..873660a
--- /dev/null
@@ -0,0 +1,31 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![allow(warnings)]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub extern "C" fn abi(a: TokenStream) -> TokenStream {
+    //~^ ERROR proc macro functions may not be `extern "C"`
+    a
+}
+
+#[proc_macro]
+pub extern "system" fn abi2(a: TokenStream) -> TokenStream {
+    //~^ ERROR proc macro functions may not be `extern "system"`
+    a
+}
+
+#[proc_macro]
+pub extern fn abi3(a: TokenStream) -> TokenStream {
+    //~^ ERROR proc macro functions may not be `extern "C"`
+    a
+}
+
+#[proc_macro]
+pub extern "Rust" fn abi4(a: TokenStream) -> TokenStream {
+    a
+}
diff --git a/tests/ui/proc-macro/proc-macro-abi.stderr b/tests/ui/proc-macro/proc-macro-abi.stderr
new file mode 100644 (file)
index 0000000..9a781be
--- /dev/null
@@ -0,0 +1,20 @@
+error: proc macro functions may not be `extern "C"`
+  --> $DIR/proc-macro-abi.rs:11:1
+   |
+LL | pub extern "C" fn abi(a: TokenStream) -> TokenStream {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: proc macro functions may not be `extern "system"`
+  --> $DIR/proc-macro-abi.rs:17:1
+   |
+LL | pub extern "system" fn abi2(a: TokenStream) -> TokenStream {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: proc macro functions may not be `extern "C"`
+  --> $DIR/proc-macro-abi.rs:23:1
+   |
+LL | pub extern fn abi3(a: TokenStream) -> TokenStream {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/proc-macro/signature-proc-macro-attribute.rs b/tests/ui/proc-macro/signature-proc-macro-attribute.rs
new file mode 100644 (file)
index 0000000..51abc8e
--- /dev/null
@@ -0,0 +1,32 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn bad_input(input: String) -> TokenStream {
+    //~^ ERROR mismatched attribute proc macro signature
+    ::proc_macro::TokenStream::new()
+}
+
+#[proc_macro_attribute]
+pub fn bad_output(input: TokenStream) -> String {
+    //~^ ERROR mismatched attribute proc macro signature
+    //~| ERROR mismatched attribute proc macro signature
+    String::from("blah")
+}
+
+#[proc_macro_attribute]
+pub fn bad_everything(input: String) -> String {
+    //~^ ERROR mismatched attribute proc macro signature
+    //~| ERROR mismatched attribute proc macro signature
+    input
+}
+
+#[proc_macro_attribute]
+pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
+    //~^ ERROR mismatched attribute proc macro signature
+}
diff --git a/tests/ui/proc-macro/signature-proc-macro-attribute.stderr b/tests/ui/proc-macro/signature-proc-macro-attribute.stderr
new file mode 100644 (file)
index 0000000..abf7a6f
--- /dev/null
@@ -0,0 +1,42 @@
+error: mismatched attribute proc macro signature
+  --> $DIR/signature-proc-macro-attribute.rs:10:1
+   |
+LL | pub fn bad_input(input: String) -> TokenStream {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attribute proc macro must have two arguments of type `proc_macro::TokenStream`
+
+error: mismatched attribute proc macro signature
+  --> $DIR/signature-proc-macro-attribute.rs:16:42
+   |
+LL | pub fn bad_output(input: TokenStream) -> String {
+   |                                          ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |
+   = note: attribute proc macros must have a signature of `fn(TokenStream, TokenStream) -> TokenStream`
+
+error: mismatched attribute proc macro signature
+  --> $DIR/signature-proc-macro-attribute.rs:16:1
+   |
+LL | pub fn bad_output(input: TokenStream) -> String {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attribute proc macro must have two arguments of type `proc_macro::TokenStream`
+
+error: mismatched attribute proc macro signature
+  --> $DIR/signature-proc-macro-attribute.rs:23:41
+   |
+LL | pub fn bad_everything(input: String) -> String {
+   |                                         ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |
+   = note: attribute proc macros must have a signature of `fn(TokenStream, TokenStream) -> TokenStream`
+
+error: mismatched attribute proc macro signature
+  --> $DIR/signature-proc-macro-attribute.rs:23:1
+   |
+LL | pub fn bad_everything(input: String) -> String {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attribute proc macro must have two arguments of type `proc_macro::TokenStream`
+
+error: mismatched attribute proc macro signature
+  --> $DIR/signature-proc-macro-attribute.rs:30:49
+   |
+LL | pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
+   |                                                 ^^^^^^^^^ found unexpected argument
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/proc-macro/signature-proc-macro-derive.rs b/tests/ui/proc-macro/signature-proc-macro-derive.rs
new file mode 100644 (file)
index 0000000..f2fd824
--- /dev/null
@@ -0,0 +1,31 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(Blah)]
+pub fn bad_input(input: String) -> TokenStream {
+    //~^ ERROR mismatched derive proc macro signature
+    TokenStream::new()
+}
+
+#[proc_macro_derive(Bleh)]
+pub fn bad_output(input: TokenStream) -> String {
+    //~^ ERROR mismatched derive proc macro signature
+    String::from("blah")
+}
+
+#[proc_macro_derive(Bluh)]
+pub fn bad_everything(input: String) -> String {
+    //~^ ERROR mismatched derive proc macro signature
+    //~| ERROR mismatched derive proc macro signature
+    input
+}
+
+#[proc_macro_derive(Blih)]
+pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
+    //~^ ERROR mismatched derive proc macro signature
+}
diff --git a/tests/ui/proc-macro/signature-proc-macro-derive.stderr b/tests/ui/proc-macro/signature-proc-macro-derive.stderr
new file mode 100644 (file)
index 0000000..a358ae2
--- /dev/null
@@ -0,0 +1,40 @@
+error: mismatched derive proc macro signature
+  --> $DIR/signature-proc-macro-derive.rs:10:25
+   |
+LL | pub fn bad_input(input: String) -> TokenStream {
+   |                         ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |
+   = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+
+error: mismatched derive proc macro signature
+  --> $DIR/signature-proc-macro-derive.rs:16:42
+   |
+LL | pub fn bad_output(input: TokenStream) -> String {
+   |                                          ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |
+   = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+
+error: mismatched derive proc macro signature
+  --> $DIR/signature-proc-macro-derive.rs:22:41
+   |
+LL | pub fn bad_everything(input: String) -> String {
+   |                                         ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |
+   = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+
+error: mismatched derive proc macro signature
+  --> $DIR/signature-proc-macro-derive.rs:22:30
+   |
+LL | pub fn bad_everything(input: String) -> String {
+   |                              ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |
+   = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+
+error: mismatched derive proc macro signature
+  --> $DIR/signature-proc-macro-derive.rs:29:33
+   |
+LL | pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^ found unexpected arguments
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/proc-macro/signature-proc-macro.rs b/tests/ui/proc-macro/signature-proc-macro.rs
new file mode 100644 (file)
index 0000000..54770aa
--- /dev/null
@@ -0,0 +1,31 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro]
+pub fn bad_input(input: String) -> TokenStream {
+    //~^ ERROR mismatched function-like proc macro signature
+    ::proc_macro::TokenStream::new()
+}
+
+#[proc_macro]
+pub fn bad_output(input: TokenStream) -> String {
+    //~^ ERROR mismatched function-like proc macro signature
+    String::from("blah")
+}
+
+#[proc_macro]
+pub fn bad_everything(input: String) -> String {
+    //~^ ERROR mismatched function-like proc macro signature
+    //~| ERROR mismatched function-like proc macro signature
+    input
+}
+
+#[proc_macro]
+pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
+    //~^ ERROR mismatched function-like proc macro signature
+}
diff --git a/tests/ui/proc-macro/signature-proc-macro.stderr b/tests/ui/proc-macro/signature-proc-macro.stderr
new file mode 100644 (file)
index 0000000..4b14a54
--- /dev/null
@@ -0,0 +1,40 @@
+error: mismatched function-like proc macro signature
+  --> $DIR/signature-proc-macro.rs:10:25
+   |
+LL | pub fn bad_input(input: String) -> TokenStream {
+   |                         ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |
+   = note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+
+error: mismatched function-like proc macro signature
+  --> $DIR/signature-proc-macro.rs:16:42
+   |
+LL | pub fn bad_output(input: TokenStream) -> String {
+   |                                          ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |
+   = note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+
+error: mismatched function-like proc macro signature
+  --> $DIR/signature-proc-macro.rs:22:41
+   |
+LL | pub fn bad_everything(input: String) -> String {
+   |                                         ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |
+   = note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+
+error: mismatched function-like proc macro signature
+  --> $DIR/signature-proc-macro.rs:22:30
+   |
+LL | pub fn bad_everything(input: String) -> String {
+   |                              ^^^^^^ found std::string::String, expected type `proc_macro::TokenStream`
+   |
+   = note: function-like proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+
+error: mismatched function-like proc macro signature
+  --> $DIR/signature-proc-macro.rs:29:33
+   |
+LL | pub fn too_many(a: TokenStream, b: TokenStream, c: String) -> TokenStream {
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^ found unexpected arguments
+
+error: aborting due to 5 previous errors
+
index 2302238253e82e172cf2a6ab068a2b5bdbdb3643..11187aa31bd8071c6047c1568bf7ac7373bbc30b 100644 (file)
@@ -8,6 +8,10 @@
 
 #[proc_macro_derive(A)]
 pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
-    //~^ ERROR: expected a `Fn<(proc_macro::TokenStream,)>` closure, found `unsafe extern "C" fn
+    //~^ ERROR: mismatched derive proc macro signature
+    //~| mismatched derive proc macro signature
+    //~| mismatched derive proc macro signature
+    //~| proc macro functions may not be `extern
+    //~| proc macro functions may not be `unsafe
     loop {}
 }
index 79f2001da005510f915eb3f696d550df0364f3c8..3dbe3f22a0df89310dbcb24e8fdb51e021e50754 100644 (file)
@@ -1,20 +1,36 @@
-error[E0277]: expected a `Fn<(proc_macro::TokenStream,)>` closure, found `unsafe extern "C" fn(i32, u32) -> u32 {foo}`
+error: proc macro functions may not be `extern "C"`
   --> $DIR/signature.rs:10:1
    |
-LL | / pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
-LL | |
-LL | |     loop {}
-LL | | }
-   | | ^
-   | | |
-   | |_call the function in a closure: `|| unsafe { /* code */ }`
-   |   required by a bound introduced by this call
+LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: proc macro functions may not be `unsafe`
+  --> $DIR/signature.rs:10:1
+   |
+LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: mismatched derive proc macro signature
+  --> $DIR/signature.rs:10:49
+   |
+LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
+   |                                                 ^^^ found u32, expected type `proc_macro::TokenStream`
+   |
+   = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+
+error: mismatched derive proc macro signature
+  --> $DIR/signature.rs:10:33
+   |
+LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
+   |                                 ^^^ found i32, expected type `proc_macro::TokenStream`
+   |
+   = note: derive proc macros must have a signature of `fn(TokenStream) -> TokenStream`
+
+error: mismatched derive proc macro signature
+  --> $DIR/signature.rs:10:38
    |
-   = help: the trait `Fn<(proc_macro::TokenStream,)>` is not implemented for fn item `unsafe extern "C" fn(i32, u32) -> u32 {foo}`
-   = note: unsafe function cannot be called generically without an unsafe block
-note: required by a bound in `ProcMacro::custom_derive`
-  --> $SRC_DIR/proc_macro/src/bridge/client.rs:LL:COL
+LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
+   |                                      ^^^^^^ found unexpected argument
 
-error: aborting due to previous error
+error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
index 65fec3becaceed9b376b13d9dbaaa4476fbb9861..91aacedfc577897b70c0bad4de441d3633bd38a4 100644 (file)
@@ -3,6 +3,7 @@
 #![feature(rustc_attrs)]
 
 use std::{
+    cell::Cell,
     ops::{Deref, CoerceUnsized, DispatchFromDyn},
     marker::Unsize,
 };
@@ -20,6 +21,20 @@ fn deref(&self) -> &T {
 impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {}
 impl<T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T> {}
 
+
+struct CellPtr<'a, T: ?Sized>(Cell<&'a T>);
+
+impl<'a, T: ?Sized> Deref for CellPtr<'a, T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        self.0.get()
+    }
+}
+
+impl<'a, T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<CellPtr<'a, U>> for CellPtr<'a, T> {}
+impl<'a, T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<CellPtr<'a, U>> for CellPtr<'a, T> {}
+
 struct Wrapper<T: ?Sized>(T);
 
 impl<T: ?Sized> Deref for Wrapper<T> {
@@ -42,6 +57,7 @@ trait Trait {
     fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32;
     fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32;
     fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32;
+    fn cell(self: CellPtr<Self>) -> i32;
 }
 
 impl Trait for i32 {
@@ -54,6 +70,9 @@ fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32 {
     fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32 {
         ***self
     }
+    fn cell(self: CellPtr<Self>) -> i32 {
+        *self
+    }
 }
 
 fn main() {
@@ -65,4 +84,7 @@ fn main() {
 
     let wpw = Wrapper(Ptr(Box::new(Wrapper(7)))) as Wrapper<Ptr<Wrapper<dyn Trait>>>;
     assert_eq!(wpw.wrapper_ptr_wrapper(), 7);
+
+    let c = CellPtr(Cell::new(&8)) as CellPtr<dyn Trait>;
+    assert_eq!(c.cell(), 8);
 }
diff --git a/tests/ui/suggestions/assoc-const-without-self.rs b/tests/ui/suggestions/assoc-const-without-self.rs
new file mode 100644 (file)
index 0000000..95070ec
--- /dev/null
@@ -0,0 +1,11 @@
+struct Foo;
+
+impl Foo {
+    const A_CONST: usize = 1;
+
+    fn foo() -> usize {
+        A_CONST //~ ERROR cannot find value `A_CONST` in this scope
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/assoc-const-without-self.stderr b/tests/ui/suggestions/assoc-const-without-self.stderr
new file mode 100644 (file)
index 0000000..88d72da
--- /dev/null
@@ -0,0 +1,14 @@
+error[E0425]: cannot find value `A_CONST` in this scope
+  --> $DIR/assoc-const-without-self.rs:7:9
+   |
+LL |         A_CONST
+   |         ^^^^^^^ not found in this scope
+   |
+help: consider using the associated constant
+   |
+LL |         Self::A_CONST
+   |         ++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0425`.
index 10447ba7089caae7eff7065aefdd1ccf4b8a63f3..7b194259349b8c090f5d82d463fde2ad62897b80 100644 (file)
@@ -19,8 +19,8 @@ error: cannot move out of value because it is borrowed
 LL |     let ref _moved @ _from = String::from("foo");
    |         ----------^^^-----
    |         |            |
-   |         |            value moved into `_from` here
-   |         value borrowed, by `_moved`, here
+   |         |            value is moved into `_from` here
+   |         value is borrowed by `_moved` here
 
 error: cannot move out of value because it is borrowed
   --> $DIR/ref-pattern-binding.rs:15:9
@@ -28,8 +28,8 @@ error: cannot move out of value because it is borrowed
 LL |     let ref _moved @ S { f } = S { f: String::from("foo") };
    |         ----------^^^^^^^-^^
    |         |                |
-   |         |                value moved into `f` here
-   |         value borrowed, by `_moved`, here
+   |         |                value is moved into `f` here
+   |         value is borrowed by `_moved` here
 
 error: borrow of moved value
   --> $DIR/ref-pattern-binding.rs:18:9
diff --git a/tests/ui/traits/new-solver/async.fail.stderr b/tests/ui/traits/new-solver/async.fail.stderr
new file mode 100644 (file)
index 0000000..b395c23
--- /dev/null
@@ -0,0 +1,17 @@
+error[E0271]: expected `[async block@$DIR/async.rs:12:17: 12:25]` to be a future that resolves to `i32`, but it resolves to `()`
+  --> $DIR/async.rs:12:17
+   |
+LL |     needs_async(async {});
+   |     ----------- ^^^^^^^^ expected `i32`, found `()`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `needs_async`
+  --> $DIR/async.rs:8:31
+   |
+LL | fn needs_async(_: impl Future<Output = i32>) {}
+   |                               ^^^^^^^^^^^^ required by this bound in `needs_async`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0271`.
diff --git a/tests/ui/traits/new-solver/async.rs b/tests/ui/traits/new-solver/async.rs
new file mode 100644 (file)
index 0000000..195cc35
--- /dev/null
@@ -0,0 +1,19 @@
+// compile-flags: -Ztrait-solver=next
+// edition: 2021
+// revisions: pass fail
+//[pass] check-pass
+
+use std::future::Future;
+
+fn needs_async(_: impl Future<Output = i32>) {}
+
+#[cfg(fail)]
+fn main() {
+    needs_async(async {});
+    //[fail]~^ ERROR to be a future that resolves to `i32`, but it resolves to `()`
+}
+
+#[cfg(pass)]
+fn main() {
+    needs_async(async { 1i32 });
+}
diff --git a/tests/ui/traits/new-solver/generator.fail.stderr b/tests/ui/traits/new-solver/generator.fail.stderr
new file mode 100644 (file)
index 0000000..d94d41e
--- /dev/null
@@ -0,0 +1,64 @@
+error[E0277]: the trait bound `[generator@$DIR/generator.rs:18:21: 18:23]: Generator<A>` is not satisfied
+  --> $DIR/generator.rs:18:21
+   |
+LL |       needs_generator(|| {
+   |  _____---------------_^
+   | |     |
+   | |     required by a bound introduced by this call
+LL | |
+LL | |
+LL | |
+LL | |         yield ();
+LL | |     });
+   | |_____^ the trait `Generator<A>` is not implemented for `[generator@$DIR/generator.rs:18:21: 18:23]`
+   |
+note: required by a bound in `needs_generator`
+  --> $DIR/generator.rs:14:28
+   |
+LL | fn needs_generator(_: impl Generator<A, Yield = B, Return = C>) {}
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `needs_generator`
+
+error[E0271]: type mismatch resolving `<[generator@$DIR/generator.rs:18:21: 18:23] as Generator<A>>::Yield == B`
+  --> $DIR/generator.rs:18:21
+   |
+LL |       needs_generator(|| {
+   |  _____---------------_^
+   | |     |
+   | |     required by a bound introduced by this call
+LL | |
+LL | |
+LL | |
+LL | |         yield ();
+LL | |     });
+   | |_____^ types differ
+   |
+note: required by a bound in `needs_generator`
+  --> $DIR/generator.rs:14:41
+   |
+LL | fn needs_generator(_: impl Generator<A, Yield = B, Return = C>) {}
+   |                                         ^^^^^^^^^ required by this bound in `needs_generator`
+
+error[E0271]: type mismatch resolving `<[generator@$DIR/generator.rs:18:21: 18:23] as Generator<A>>::Return == C`
+  --> $DIR/generator.rs:18:21
+   |
+LL |       needs_generator(|| {
+   |  _____---------------_^
+   | |     |
+   | |     required by a bound introduced by this call
+LL | |
+LL | |
+LL | |
+LL | |         yield ();
+LL | |     });
+   | |_____^ types differ
+   |
+note: required by a bound in `needs_generator`
+  --> $DIR/generator.rs:14:52
+   |
+LL | fn needs_generator(_: impl Generator<A, Yield = B, Return = C>) {}
+   |                                                    ^^^^^^^^^^ required by this bound in `needs_generator`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0271, E0277.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/tests/ui/traits/new-solver/generator.rs b/tests/ui/traits/new-solver/generator.rs
new file mode 100644 (file)
index 0000000..364373c
--- /dev/null
@@ -0,0 +1,32 @@
+// compile-flags: -Ztrait-solver=next
+// edition: 2021
+// revisions: pass fail
+//[pass] check-pass
+
+#![feature(generator_trait, generators)]
+
+use std::ops::Generator;
+
+struct A;
+struct B;
+struct C;
+
+fn needs_generator(_: impl Generator<A, Yield = B, Return = C>) {}
+
+#[cfg(fail)]
+fn main() {
+    needs_generator(|| {
+        //[fail]~^ ERROR Generator<A>` is not satisfied
+        //[fail]~| ERROR as Generator<A>>::Yield == B`
+        //[fail]~| ERROR as Generator<A>>::Return == C`
+        yield ();
+    });
+}
+
+#[cfg(pass)]
+fn main() {
+    needs_generator(|_: A| {
+        let _: A = yield B;
+        C
+    })
+}
index 83d22161e4e75617fb3845576e8b6843d0eb966a..eeb5dca07f06a4bd86bc34fc0f2e2e26e5b8a7db 100644 (file)
@@ -8,7 +8,7 @@
 fn f<'a: 'static>(t: &'a str) -> X<'a> {
     //~^ WARNING unnecessary lifetime parameter
     t
-    //~^ ERROR non-defining opaque type use
+    //~^ ERROR expected generic lifetime parameter, found `'static`
 }
 
 fn extend_lt<'a>(o: &'a str) -> &'static str {
index 920eef11da4b993dcdf66fb168602371b8145781..94882597a62e6fd823ceb778ca1e5c18bebe16c8 100644 (file)
@@ -6,7 +6,7 @@ LL | fn f<'a: 'static>(t: &'a str) -> X<'a> {
    |
    = help: you can use the `'static` lifetime directly, in place of `'a`
 
-error: non-defining opaque type use in defining scope
+error[E0792]: expected generic lifetime parameter, found `'static`
   --> $DIR/bounds-are-checked.rs:10:5
    |
 LL | type X<'a> = impl Into<&'static str> + From<&'a str>;
@@ -17,3 +17,4 @@ LL |     t
 
 error: aborting due to previous error; 1 warning emitted
 
+For more information about this error, try `rustc --explain E0792`.
index f5045d382aac4ed63c4be46e727c657ea6444a1c..e7b8567b9a217d7e629343116d52655ac114e04a 100644 (file)
@@ -19,7 +19,7 @@ fn concrete_ty() -> OneTy<u32> {
 
 fn concrete_lifetime() -> OneLifetime<'static> {
     6u32
-    //~^ ERROR non-defining opaque type use in defining scope
+    //~^ ERROR expected generic lifetime parameter, found `'static`
 }
 
 fn concrete_const() -> OneConst<{ 123 }> {
index 564648630b16122127ce6a1c026785740f68c118..966fe823f024dd99e4f3e6d1e70688ffb674aa97 100644 (file)
@@ -7,7 +7,7 @@ LL | type OneTy<T> = impl Debug;
 LL |     5u32
    |     ^^^^
 
-error: non-defining opaque type use in defining scope
+error[E0792]: expected generic lifetime parameter, found `'static`
   --> $DIR/generic_nondefining_use.rs:21:5
    |
 LL | type OneLifetime<'a> = impl Debug;
diff --git a/tests/ui/typeck/bad-type-in-vec-push.rs b/tests/ui/typeck/bad-type-in-vec-push.rs
new file mode 100644 (file)
index 0000000..a807f03
--- /dev/null
@@ -0,0 +1,20 @@
+// The error message here still is pretty confusing.
+
+fn main() {
+    let mut result = vec![1];
+    // The type of `result` is constrained to be `Vec<{integer}>` here.
+    // But the logic we use to find what expression constrains a type
+    // is not sophisticated enough to know this.
+
+    let mut vector = Vec::new();
+    vector.sort();
+    result.push(vector);
+    //~^ ERROR mismatched types
+    // So it thinks that the type of `result` is constrained here.
+}
+
+fn example2() {
+    let mut x = vec![1];
+    x.push("");
+    //~^ ERROR mismatched types
+}
diff --git a/tests/ui/typeck/bad-type-in-vec-push.stderr b/tests/ui/typeck/bad-type-in-vec-push.stderr
new file mode 100644 (file)
index 0000000..e4c99ec
--- /dev/null
@@ -0,0 +1,29 @@
+error[E0308]: mismatched types
+  --> $DIR/bad-type-in-vec-push.rs:11:17
+   |
+LL |     vector.sort();
+   |     ------ here the type of `vector` is inferred to be `Vec<_>`
+LL |     result.push(vector);
+   |            ---- ^^^^^^ expected integer, found struct `Vec`
+   |            |
+   |            arguments to this method are incorrect
+   |
+   = note: expected type `{integer}`
+            found struct `Vec<_>`
+note: associated function defined here
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+
+error[E0308]: mismatched types
+  --> $DIR/bad-type-in-vec-push.rs:18:12
+   |
+LL |     x.push("");
+   |       ---- ^^ expected integer, found `&str`
+   |       |
+   |       arguments to this method are incorrect
+   |
+note: associated function defined here
+  --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
index 16a3132151374d31dda0f22a0e822163a41e477b..79958729fc521ed1ada06422e092a769384d2377 100644 (file)
@@ -456,6 +456,9 @@ These commits modify **compiler targets**.
 (See the [Target Tier Policy](https://doc.rust-lang.org/nightly/rustc/target-tier-policy.html).)
 """
 
+[mentions."src/doc/style-guide"]
+cc = ["@rust-lang/style"]
+
 [assign]
 warn_non_default_branch = true
 contributing_url = "https://rustc-dev-guide.rust-lang.org/contributing.html"
@@ -560,6 +563,12 @@ ast_lowering = [
 fallback = [
     "@Mark-Simulacrum"
 ]
+style-team = [
+    "@calebcartwright",
+    "@compiler-errors",
+    "@joshtriplett",
+    "@yaahc",
+]
 
 [assign.owners]
 "/.github/workflows" =                       ["infra-ci"]
@@ -604,6 +613,7 @@ fallback = [
 "/src/doc/rust-by-example" =                 ["@ehuss"]
 "/src/doc/rustc-dev-guide" =                 ["@ehuss"]
 "/src/doc/rustdoc" =                         ["rustdoc"]
+"/src/doc/style-guide" =                     ["style-team"]
 "/src/etc" =                                 ["@Mark-Simulacrum"]
 "/src/librustdoc" =                          ["rustdoc"]
 "/src/llvm-project" =                        ["@cuviper"]