From dbf701838758bd70d51fa36dcb79e7d02e0e4352 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petteri=20R=C3=A4ty?= Date: Mon, 24 Jun 2024 11:12:10 +0300 Subject: [PATCH 01/12] Fix simd_gather documentation There is no idx in the function signature. --- library/core/src/intrinsics/simd.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index 4be5e62ea5bc6..b892e11158822 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -263,9 +263,6 @@ extern "rust-intrinsic" { /// /// `V` must be a vector of integers with the same length as `T` (but any element size). /// - /// `idx` must be a constant: either naming a constant item, or an inline - /// `const {}` expression. - /// /// For each pointer in `ptr`, if the corresponding value in `mask` is `!0`, read the pointer. /// Otherwise if the corresponding value in `mask` is `0`, return the corresponding value from /// `val`. From c053e8939bae9c052ff53f58e692408a8099df5d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 5 Jun 2024 18:06:09 +1000 Subject: [PATCH 02/12] Remove the `box_pointers` lint. As the comment says, this lint "is mostly historical, and not particularly useful". It's not worth keeping it around. --- compiler/rustc_lint/messages.ftl | 2 - compiler/rustc_lint/src/builtin.rs | 82 +------------------ compiler/rustc_lint/src/lib.rs | 5 +- compiler/rustc_lint/src/lints.rs | 6 -- .../crates/ide-db/src/generated/lints.rs | 1 - tests/ui/lint/lint-owned-heap-memory.rs | 12 --- tests/ui/lint/lint-owned-heap-memory.stderr | 20 ----- tests/ui/lint/reasons-erroneous.rs | 2 +- tests/ui/lint/reasons-erroneous.stderr | 6 +- 9 files changed, 11 insertions(+), 125 deletions(-) delete mode 100644 tests/ui/lint/lint-owned-heap-memory.rs delete mode 100644 tests/ui/lint/lint-owned-heap-memory.stderr diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 46cf87d1e3c17..3e952558d29d3 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -56,8 +56,6 @@ lint_builtin_asm_labels = avoid using named labels in inline assembly .help = only local labels of the form `:` should be used in inline asm .note = see the asm section of Rust By Example for more information -lint_builtin_box_pointers = type uses owned (Box type) pointers: {$ty} - lint_builtin_clashing_extern_diff_name = `{$this}` redeclares `{$orig}` with a different signature .previous_decl_label = `{$orig}` previously declared here .mismatch_label = this signature doesn't match the previous declaration diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 98318cd14d9dc..79c8046f9b741 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -24,9 +24,9 @@ use crate::fluent_generated as fluent; use crate::{ errors::BuiltinEllipsisInclusiveRangePatterns, lints::{ - BuiltinAnonymousParams, BuiltinBoxPointers, BuiltinConstNoMangle, - BuiltinDeprecatedAttrLink, BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed, - BuiltinDerefNullptr, BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives, + BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink, + BuiltinDeprecatedAttrLinkSuggestion, BuiltinDeprecatedAttrUsed, BuiltinDerefNullptr, + BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives, BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures, BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents, BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc, @@ -56,7 +56,6 @@ use rustc_middle::bug; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::GenericArgKind; use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::Upcast; use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef}; @@ -134,80 +133,6 @@ impl EarlyLintPass for WhileTrue { } } -declare_lint! { - /// The `box_pointers` lints use of the Box type. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #![deny(box_pointers)] - /// struct Foo { - /// x: Box, - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// This lint is mostly historical, and not particularly useful. `Box` - /// used to be built into the language, and the only way to do heap - /// allocation. Today's Rust can call into other allocators, etc. - BOX_POINTERS, - Allow, - "use of owned (Box type) heap memory" -} - -declare_lint_pass!(BoxPointers => [BOX_POINTERS]); - -impl BoxPointers { - fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) { - for leaf in ty.walk() { - if let GenericArgKind::Type(leaf_ty) = leaf.unpack() - && leaf_ty.is_box() - { - cx.emit_span_lint(BOX_POINTERS, span, BuiltinBoxPointers { ty }); - } - } - } -} - -impl<'tcx> LateLintPass<'tcx> for BoxPointers { - fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { - match it.kind { - hir::ItemKind::Fn(..) - | hir::ItemKind::TyAlias(..) - | hir::ItemKind::Enum(..) - | hir::ItemKind::Struct(..) - | hir::ItemKind::Union(..) => self.check_heap_type( - cx, - it.span, - cx.tcx.type_of(it.owner_id).instantiate_identity(), - ), - _ => (), - } - - // If it's a struct, we also have to check the fields' types - match it.kind { - hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => { - for field in struct_def.fields() { - self.check_heap_type( - cx, - field.span, - cx.tcx.type_of(field.def_id).instantiate_identity(), - ); - } - } - _ => (), - } - } - - fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) { - let ty = cx.typeck_results().node_type(e.hir_id); - self.check_heap_type(cx, e.span, ty); - } -} - declare_lint! { /// The `non_shorthand_field_patterns` lint detects using `Struct { x: x }` /// instead of `Struct { x }` in a pattern. @@ -1640,7 +1565,6 @@ declare_lint_pass!( /// which are used by other parts of the compiler. SoftLints => [ WHILE_TRUE, - BOX_POINTERS, NON_SHORTHAND_FIELD_PATTERNS, UNSAFE_CODE, MISSING_DOCS, diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 7dae2de7bfb58..17f9d4421aef2 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -187,7 +187,6 @@ late_lint_methods!( ImproperCTypesDefinitions: ImproperCTypesDefinitions, InvalidFromUtf8: InvalidFromUtf8, VariantSizeDifferences: VariantSizeDifferences, - BoxPointers: BoxPointers, PathStatements: PathStatements, LetUnderscore: LetUnderscore, InvalidReferenceCasting: InvalidReferenceCasting, @@ -551,6 +550,10 @@ fn register_builtins(store: &mut LintStore) { "converted into hard error, see RFC #3535 \ for more information", ); + store.register_removed( + "box_pointers", + "it does not detect other kinds of allocations, and existed only for historical reasons", + ); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 14084405d0ee1..7c5640f5959a0 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -66,12 +66,6 @@ pub struct BuiltinWhileTrue { pub replace: String, } -#[derive(LintDiagnostic)] -#[diag(lint_builtin_box_pointers)] -pub struct BuiltinBoxPointers<'a> { - pub ty: Ty<'a>, -} - #[derive(LintDiagnostic)] #[diag(lint_builtin_non_shorthand_field_patterns)] pub struct BuiltinNonShorthandFieldPatterns { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs index c92d4e78ffa71..7755a9b9748be 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs @@ -49,7 +49,6 @@ pub const DEFAULT_LINTS: &[Lint] = &[ label: "bindings_with_variant_name", description: r##"detects pattern bindings with the same name as one of the matched variants"##, }, - Lint { label: "box_pointers", description: r##"use of owned (Box type) heap memory"## }, Lint { label: "break_with_label_and_loop", description: r##"`break` expression with label and unlabeled loop as value expression"##, diff --git a/tests/ui/lint/lint-owned-heap-memory.rs b/tests/ui/lint/lint-owned-heap-memory.rs deleted file mode 100644 index af47d5c072005..0000000000000 --- a/tests/ui/lint/lint-owned-heap-memory.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![allow(dead_code)] -#![forbid(box_pointers)] - - -struct Foo { - x: Box //~ ERROR type uses owned -} - -fn main() { - let _x: Foo = Foo { x : Box::new(10) }; - //~^ ERROR type uses owned -} diff --git a/tests/ui/lint/lint-owned-heap-memory.stderr b/tests/ui/lint/lint-owned-heap-memory.stderr deleted file mode 100644 index 5ba3969707571..0000000000000 --- a/tests/ui/lint/lint-owned-heap-memory.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: type uses owned (Box type) pointers: Box - --> $DIR/lint-owned-heap-memory.rs:6:5 - | -LL | x: Box - | ^^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/lint-owned-heap-memory.rs:2:11 - | -LL | #![forbid(box_pointers)] - | ^^^^^^^^^^^^ - -error: type uses owned (Box type) pointers: Box - --> $DIR/lint-owned-heap-memory.rs:10:29 - | -LL | let _x: Foo = Foo { x : Box::new(10) }; - | ^^^^^^^^^^^^ - -error: aborting due to 2 previous errors - diff --git a/tests/ui/lint/reasons-erroneous.rs b/tests/ui/lint/reasons-erroneous.rs index 244b376b60d88..0aa46953bf1ac 100644 --- a/tests/ui/lint/reasons-erroneous.rs +++ b/tests/ui/lint/reasons-erroneous.rs @@ -9,7 +9,7 @@ #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides their bearings lost")] //~^ ERROR malformed lint attribute //~| NOTE bad attribute argument -#![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")] +#![warn(unsafe_code, blerp = "or in league with robbers have reversed the signposts")] //~^ ERROR malformed lint attribute //~| NOTE bad attribute argument #![warn(elided_lifetimes_in_paths, reason("disrespectful to ancestors", "irresponsible to heirs"))] diff --git a/tests/ui/lint/reasons-erroneous.stderr b/tests/ui/lint/reasons-erroneous.stderr index adc97174b99cd..fcff88d8e0fa7 100644 --- a/tests/ui/lint/reasons-erroneous.stderr +++ b/tests/ui/lint/reasons-erroneous.stderr @@ -17,10 +17,10 @@ LL | #![warn(bare_trait_objects, reasons = "leaders to no sure land, guides thei | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument error[E0452]: malformed lint attribute input - --> $DIR/reasons-erroneous.rs:12:23 + --> $DIR/reasons-erroneous.rs:12:22 | -LL | #![warn(box_pointers, blerp = "or in league with robbers have reversed the signposts")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument +LL | #![warn(unsafe_code, blerp = "or in league with robbers have reversed the signposts")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad attribute argument error[E0452]: malformed lint attribute input --> $DIR/reasons-erroneous.rs:15:36 From 64be3a3ea756cea1397476e93968673d88770db0 Mon Sep 17 00:00:00 2001 From: WANG Xuerui Date: Fri, 28 Jun 2024 01:52:59 +0800 Subject: [PATCH 03/12] Update the LoongArch target documentation The docs for the LoongArch targets are a bit dated since their introduction, and the prose has some room for improvement as well. Streamline a bit, referring to the neighboring targets' docs, and provide up-to-date information as much as I can come up with. --- .../src/platform-support/loongarch-linux.md | 139 ++++++++++++------ .../src/platform-support/loongarch-none.md | 56 ++++--- 2 files changed, 125 insertions(+), 70 deletions(-) diff --git a/src/doc/rustc/src/platform-support/loongarch-linux.md b/src/doc/rustc/src/platform-support/loongarch-linux.md index e8f55b8bfce10..45eb0a81216d8 100644 --- a/src/doc/rustc/src/platform-support/loongarch-linux.md +++ b/src/doc/rustc/src/platform-support/loongarch-linux.md @@ -1,30 +1,24 @@ -# loongarch\*-unknown-linux-\* +# `loongarch*-unknown-linux-*` -**Tier: 2** +**Tier: 2 (with Host Tools)** -[LoongArch] is a new RISC ISA developed by Loongson Technology Corporation Limited. +[LoongArch][la-docs] Linux targets. +LoongArch is a RISC ISA developed by Loongson Technology Corporation Limited. -[LoongArch]: https://loongson.github.io/LoongArch-Documentation/README-EN.html +| Target | Description | +|--------|-------------| +| `loongarch64-unknown-linux-gnu` | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36) | +| `loongarch64-unknown-linux-musl` | LoongArch64 Linux, LP64D ABI (kernel 5.19, musl 1.2.5) | -The target name follow this format: `--`, where `` specifies the CPU family/model, `` specifies the vendor and `` the operating system name. -While the integer base ABI is implied by the machine field, the floating point base ABI type is encoded into the os field of the specifier using the string suffix ``. +These support both native and cross builds, and have full support for `std`. -| `` | `Description` | -|------------------------|--------------------------------------------------------------------| -| f64 | The base ABI use 64-bits FPRs for parameter passing. (lp64d)| -| f32 | The base ABI uses 32-bit FPRs for parameter passing. (lp64f)| -| sf | The base ABI uses no FPR for parameter passing. (lp64s) | +Reference material: -
+* [LoongArch ISA manuals][la-docs] +* [Application Binary Interface for the LoongArch™ Architecture][la-abi-specs] -|`ABI type(Base ABI/ABI extension)`| `C library` | `kernel` | `target tuple` | -|----------------------------------|-------------|----------|----------------------------------| -| lp64d/base | glibc | linux | loongarch64-unknown-linux-gnu | -| lp64f/base | glibc | linux | loongarch64-unknown-linux-gnuf32 | -| lp64s/base | glibc | linux | loongarch64-unknown-linux-gnusf | -| lp64d/base | musl libc | linux | loongarch64-unknown-linux-musl| -| lp64f/base | musl libc | linux | loongarch64-unknown-linux-muslf32| -| lp64s/base | musl libc | linux | loongarch64-unknown-linux-muslsf | +[la-abi-specs]: https://github.com/loongson/la-abi-specs +[la-docs]: https://loongson.github.io/LoongArch-Documentation/README-EN.html ## Target maintainers @@ -35,23 +29,57 @@ While the integer base ABI is implied by the machine field, the floating po ## Requirements -This target is cross-compiled. -A GNU toolchain for LoongArch target is required. It can be downloaded from https://github.com/loongson/build-tools/releases, or built from the source code of GCC (12.1.0 or later) and Binutils (2.40 or later). +### OS Version -## Building the target +The minimum supported Linux version is 5.19. -The target can be built by enabling it for a `rustc` build. +Some Linux distributions, mostly commercial ones, may provide forked Linux +kernels that has a version number less than 5.19 for their LoongArch ports. +Such kernels may still get patched to be compatible with the upstream Linux +5.19 UAPI, therefore supporting the targets described in this document, but +this is not always the case. The `rustup` installer contains a check for this, +and will abort if incompatibility is detected. + +### Host toolchain + +The targets require a reasonably up-to-date LoongArch toolchain on the host. +Currently the following components are used by the Rust CI to build the target, +and the versions can be seen as the minimum requirement: + +* GNU Binutils 2.40 +* GCC 13.x +* glibc 2.36 +* linux-headers 5.19 + +Of these, glibc and linux-headers are at their respective earliest versions with +mainline LoongArch support, so it is impossible to use older versions of these. +Older versions of Binutils and GCC will not work either, due to lack of support +for newer LoongArch ELF relocation types, among other features. + +Recent LLVM/Clang toolchains may be able to build the targets, but are not +currently being actively tested. + +## Building + +These targets are distributed through `rustup`, and otherwise require no +special configuration. + +If you need to build your own Rust for some reason though, the targets can be +simply enabled in `config.toml`. For example: ```toml [build] target = ["loongarch64-unknown-linux-gnu"] ``` -Make sure `loongarch64-unknown-linux-gnu-gcc` can be searched from the directories specified in`$PATH`. Alternatively, you can use GNU LoongArch Toolchain by adding the following to `config.toml`: +Make sure the LoongArch toolchain binaries are reachable from `$PATH`. +Alternatively, you can explicitly configure the paths in `config.toml`: ```toml [target.loongarch64-unknown-linux-gnu] -# ADJUST THIS PATH TO POINT AT YOUR TOOLCHAIN +# Adjust the paths to point at your toolchain +# Suppose the toolchain is placed at /TOOLCHAIN_PATH, and the cross prefix is +# "loongarch64-unknown-linux-gnu-": cc = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc" cxx = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-g++" ar = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-ar" @@ -59,36 +87,51 @@ ranlib = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-ranlib" linker = "/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc" ``` -## Cross-compilation +### Cross-compilation -This target can be cross-compiled on a `x86_64-unknown-linux-gnu` host. Cross-compilation on other hosts may work but is not tested. +This target can be cross-compiled on a `x86_64-unknown-linux-gnu` host. +Other hosts are also likely to work, but not actively tested. + +You can test the cross build directly on the host, thanks to QEMU linux-user emulation. +An example is given below: + +```sh +# Suppose the cross toolchain is placed at $TOOLCHAIN_PATH, with a cross prefix +# of "loongarch64-unknown-linux-gnu-". +export CC_loongarch64_unknown_linux_gnu="$TOOLCHAIN_PATH"/bin/loongarch64-unknown-linux-gnu-gcc +export CXX_loongarch64_unknown_linux_gnu="$TOOLCHAIN_PATH"/bin/loongarch64-unknown-linux-gnu-g++ +export AR_loongarch64_unknown_linux_gnu="$TOOLCHAIN_PATH"/bin/loongarch64-unknown-linux-gnu-gcc-ar +export CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_LINKER="$TOOLCHAIN_PATH"/bin/loongarch64-unknown-linux-gnu-gcc + +# Point qemu-loongarch64 to the LoongArch sysroot. +# Suppose the sysroot is located at "sysroot" below the toolchain root: +export CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNU_RUNNER="qemu-loongarch64 -L $TOOLCHAIN_PATH/sysroot" +# Or alternatively, if binfmt_misc is set up for running LoongArch binaries +# transparently: +export QEMU_LD_PREFIX="$TOOLCHAIN_PATH"/sysroot -## Testing -To test a cross-compiled binary on your build system, install the qemu binary that supports the LoongArch architecture and execute the following commands. -```text -CC_loongarch64_unknown_linux_gnu=/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc \ -CXX_loongarch64_unknown_linux_gnu=/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-g++ \ -AR_loongarch64_unknown_linux_gnu=/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc-ar \ -CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNUN_LINKER=/TOOLCHAIN_PATH/bin/loongarch64-unknown-linux-gnu-gcc \ -# SET TARGET SYSTEM LIBRARY PATH -CARGO_TARGET_LOONGARCH64_UNKNOWN_LINUX_GNUN_RUNNER="qemu-loongarch64 -L /TOOLCHAIN_PATH/TARGET_LIBRARY_PATH" \ cargo run --target loongarch64-unknown-linux-gnu --release ``` -Tested on x86 architecture, other architectures not tested. -## Building Rust programs +## Testing + +There are no special requirements for testing and running the targets. +For testing cross builds on the host, please refer to the "Cross-compilation" +section above. -Rust does not yet ship pre-compiled artifacts for this target. To compile for this target, you will either need to build Rust with the target enabled (see "Building the target" above), or build your own copy of `std` by using `build-std` or similar. +## Building Rust programs -If `rustc` has support for that target and the library artifacts are available, then Rust static libraries can be built for that target: +As the targets are available through `rustup`, it is very easy to build Rust +programs for these targets: same as with other architectures. +Note that you will need a LoongArch C/C++ toolchain for linking, or if you want +to compile C code along with Rust (such as for Rust crates with C dependencies). -```shell -$ rustc --target loongarch64-unknown-linux-gnu your-code.rs --crate-type staticlib -$ ls libyour_code.a +```sh +rustup target add loongarch64-unknown-linux-gnu +cargo build --target loongarch64-unknown-linux-gnu ``` -On Rust Nightly it's possible to build without the target artifacts available: +Availability of pre-built artifacts through `rustup` are as follows: -```text -cargo build -Z build-std --target loongarch64-unknown-linux-gnu -``` +* `loongarch64-unknown-linux-gnu`: since Rust 1.71; +* `loongarch64-unknown-linux-musl`: since Rust 1.81. diff --git a/src/doc/rustc/src/platform-support/loongarch-none.md b/src/doc/rustc/src/platform-support/loongarch-none.md index 68d7c9d85e444..110a7cc3424d4 100644 --- a/src/doc/rustc/src/platform-support/loongarch-none.md +++ b/src/doc/rustc/src/platform-support/loongarch-none.md @@ -4,10 +4,10 @@ Freestanding/bare-metal LoongArch64 binaries in ELF format: firmware, kernels, etc. -| Target | Descriptions | -|------------------------------------|-------------------------------------------------------| -| loongarch64-unknown-none | LoongArch 64-bit, LP64D ABI (freestanding, hardfloat) | -| loongarch64-unknown-none-softfloat | LoongArch 64-bit, LP64S ABI (freestanding, softfloat) | +| Target | Description | +|--------|-------------| +| `loongarch64-unknown-none` | LoongArch 64-bit, LP64D ABI (freestanding, hard-float) | +| `loongarch64-unknown-none-softfloat` | LoongArch 64-bit, LP64S ABI (freestanding, soft-float) | ## Target maintainers @@ -19,6 +19,8 @@ Freestanding/bare-metal LoongArch64 binaries in ELF format: firmware, kernels, e This target is cross-compiled. There is no support for `std`. There is no default allocator, but it's possible to use `alloc` by supplying an allocator. +The `*-softfloat` target does not assume existence of FPU or any other LoongArch +ISA extension, and does not make use of any non-GPR register. This allows the generated code to run in environments, such as kernels, which may need to avoid the use of such registers or which may have special considerations about the use of such registers (e.g. saving and restoring them to avoid breaking @@ -26,54 +28,64 @@ userspace code using the same registers). You can change code generation to use additional CPU features via the `-C target-feature=` codegen options to rustc, or via the `#[target_feature]` mechanism within Rust code. -By default, code generated with this target should run on any `loongarch` -hardware; enabling additional target features may raise this baseline. +By default, code generated with the soft-float target should run on any +LoongArch64 hardware, with the hard-float target additionally requiring an FPU; +enabling additional target features may raise this baseline. -Code generated with this target will use the `small` code model by default. +Code generated with the targets will use the `small` code model by default. You can change this using the `-C code-model=` option to rustc. -On `loongarch64-unknown-none*`, `extern "C"` uses the [standard calling -convention](https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html). +On `loongarch64-unknown-none*`, `extern "C"` uses the [architecture's standard calling convention][lapcs]. -This target generates binaries in the ELF format. Any alternate formats or +[lapcs]: https://github.com/loongson/la-abi-specs/blob/release/lapcs.adoc + +The targets generate binaries in the ELF format. Any alternate formats or special considerations for binary layout will require linker options or linker scripts. ## Building the target -You can build Rust with support for the target by adding it to the `target` +You can build Rust with support for the targets by adding them to the `target` list in `config.toml`: ```toml [build] build-stage = 1 -target = ["loongarch64-unknown-none"] +target = [ + "loongarch64-unknown-none", + "loongarch64-unknown-none-softfloat", +] ``` +## Testing + +As the targets support a variety of different environments and do not support +`std`, they do not support running the Rust test suite. + ## Building Rust programs -```text +Starting with Rust 1.74, precompiled artifacts are provided via `rustup`: + +```sh +# install cross-compile toolchain +rustup target add loongarch64-unknown-none # target flag may be used with any cargo or rustc command cargo build --target loongarch64-unknown-none ``` -## Testing - -As `loongarch64-unknown-none*` supports a variety of different environments and does -not support `std`, this target does not support running the Rust test suite. - ## Cross-compilation toolchains and C code -If you want to compile C code along with Rust (such as for Rust crates with C -dependencies), you will need an appropriate `loongarch` toolchain. +For cross builds, you will need an appropriate LoongArch C/C++ toolchain for +linking, or if you want to compile C code along with Rust (such as for Rust +crates with C dependencies). Rust *may* be able to use an `loongarch64-unknown-linux-gnu-` toolchain with appropriate standalone flags to build for this toolchain (depending on the assumptions of that toolchain, see below), or you may wish to use a separate `loongarch64-unknown-none` toolchain. -On some `loongarch` hosts that use ELF binaries, you *may* be able to use the host +On some LoongArch hosts that use ELF binaries, you *may* be able to use the host C toolchain, if it does not introduce assumptions about the host environment that don't match the expectations of a standalone environment. Otherwise, you may need a separate toolchain for standalone/freestanding development, just as -when cross-compiling from a non-`loongarch` platform. +when cross-compiling from a non-LoongArch platform. From 35f209361fcd0751b3d260d67962b0af2d455596 Mon Sep 17 00:00:00 2001 From: Sky Date: Thu, 27 Jun 2024 22:27:59 -0400 Subject: [PATCH 04/12] small correction to fmt::Pointer impl the `expose_provenance` method does not require `T: Sized` --- library/core/src/fmt/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index c25bc5a1b13c9..69ccc6ce3ca3d 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -2478,8 +2478,7 @@ impl Display for char { #[stable(feature = "rust1", since = "1.0.0")] impl Pointer for *const T { fn fmt(&self, f: &mut Formatter<'_>) -> Result { - // Cast is needed here because `.expose_provenance()` requires `T: Sized`. - pointer_fmt_inner((*self as *const ()).expose_provenance(), f) + pointer_fmt_inner(self.expose_provenance(), f) } } From 617de8cfb59252a501fc7e0ab7c2510dd8a8a7f4 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 30 Jun 2024 17:36:16 +1000 Subject: [PATCH 05/12] coverage: Move span unexpansion into its own submodule --- .../src/coverage/mappings.rs | 5 +- .../rustc_mir_transform/src/coverage/mod.rs | 1 + .../rustc_mir_transform/src/coverage/spans.rs | 5 -- .../src/coverage/spans/from_mir.rs | 56 +------------------ .../src/coverage/unexpand.rs | 54 ++++++++++++++++++ 5 files changed, 59 insertions(+), 62 deletions(-) create mode 100644 compiler/rustc_mir_transform/src/coverage/unexpand.rs diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index 759bb7c1f9d96..e003de4e1fd71 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -9,9 +9,8 @@ use rustc_middle::ty::TyCtxt; use rustc_span::Span; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; -use crate::coverage::spans::{ - extract_refined_covspans, unexpand_into_body_span_with_visible_macro, -}; +use crate::coverage::spans::extract_refined_covspans; +use crate::coverage::unexpand::unexpand_into_body_span_with_visible_macro; use crate::coverage::ExtractedHirInfo; /// Associates an ordinary executable code span with its corresponding BCB. diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index 4a64d21f3d17b..d55bde311c17e 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -6,6 +6,7 @@ mod mappings; mod spans; #[cfg(test)] mod tests; +mod unexpand; use rustc_middle::mir::coverage::{ CodeRegion, CoverageKind, DecisionInfo, FunctionCoverageInfo, Mapping, MappingKind, diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 84a70d1f02d75..7612c01c52ec4 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -14,11 +14,6 @@ use crate::coverage::ExtractedHirInfo; mod from_mir; -// FIXME(#124545) It's awkward that we have to re-export this, because it's an -// internal detail of `from_mir` that is also needed when handling branch and -// MC/DC spans. Ideally we would find a more natural home for it. -pub(super) use from_mir::unexpand_into_body_span_with_visible_macro; - pub(super) fn extract_refined_covspans( mir_body: &mir::Body<'_>, hir_info: &ExtractedHirInfo, diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 09deb7534bfde..2ca166929eec8 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -4,12 +4,13 @@ use rustc_middle::mir::{ self, AggregateKind, FakeReadCause, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; -use rustc_span::{ExpnKind, MacroKind, Span, Symbol}; +use rustc_span::{Span, Symbol}; use crate::coverage::graph::{ BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB, }; use crate::coverage::spans::Covspan; +use crate::coverage::unexpand::unexpand_into_body_span_with_visible_macro; use crate::coverage::ExtractedHirInfo; pub(crate) struct ExtractedCovspans { @@ -215,59 +216,6 @@ fn filtered_terminator_span(terminator: &Terminator<'_>) -> Option { } } -/// Returns an extrapolated span (pre-expansion[^1]) corresponding to a range -/// within the function's body source. This span is guaranteed to be contained -/// within, or equal to, the `body_span`. If the extrapolated span is not -/// contained within the `body_span`, `None` is returned. -/// -/// [^1]Expansions result from Rust syntax including macros, syntactic sugar, -/// etc.). -pub(crate) fn unexpand_into_body_span_with_visible_macro( - original_span: Span, - body_span: Span, -) -> Option<(Span, Option)> { - let (span, prev) = unexpand_into_body_span_with_prev(original_span, body_span)?; - - let visible_macro = prev - .map(|prev| match prev.ctxt().outer_expn_data().kind { - ExpnKind::Macro(MacroKind::Bang, name) => Some(name), - _ => None, - }) - .flatten(); - - Some((span, visible_macro)) -} - -/// Walks through the expansion ancestors of `original_span` to find a span that -/// is contained in `body_span` and has the same [`SyntaxContext`] as `body_span`. -/// The ancestor that was traversed just before the matching span (if any) is -/// also returned. -/// -/// For example, a return value of `Some((ancestor, Some(prev))` means that: -/// - `ancestor == original_span.find_ancestor_inside_same_ctxt(body_span)` -/// - `ancestor == prev.parent_callsite()` -/// -/// [`SyntaxContext`]: rustc_span::SyntaxContext -fn unexpand_into_body_span_with_prev( - original_span: Span, - body_span: Span, -) -> Option<(Span, Option)> { - let mut prev = None; - let mut curr = original_span; - - while !body_span.contains(curr) || !curr.eq_ctxt(body_span) { - prev = Some(curr); - curr = curr.parent_callsite()?; - } - - debug_assert_eq!(Some(curr), original_span.find_ancestor_in_same_ctxt(body_span)); - if let Some(prev) = prev { - debug_assert_eq!(Some(curr), prev.parent_callsite()); - } - - Some((curr, prev)) -} - #[derive(Debug)] pub(crate) struct Hole { pub(crate) span: Span, diff --git a/compiler/rustc_mir_transform/src/coverage/unexpand.rs b/compiler/rustc_mir_transform/src/coverage/unexpand.rs new file mode 100644 index 0000000000000..18532b8ee4581 --- /dev/null +++ b/compiler/rustc_mir_transform/src/coverage/unexpand.rs @@ -0,0 +1,54 @@ +use rustc_span::{ExpnKind, MacroKind, Span, Symbol}; + +/// Returns an extrapolated span (pre-expansion[^1]) corresponding to a range +/// within the function's body source. This span is guaranteed to be contained +/// within, or equal to, the `body_span`. If the extrapolated span is not +/// contained within the `body_span`, `None` is returned. +/// +/// [^1]Expansions result from Rust syntax including macros, syntactic sugar, +/// etc.). +pub(crate) fn unexpand_into_body_span_with_visible_macro( + original_span: Span, + body_span: Span, +) -> Option<(Span, Option)> { + let (span, prev) = unexpand_into_body_span_with_prev(original_span, body_span)?; + + let visible_macro = prev + .map(|prev| match prev.ctxt().outer_expn_data().kind { + ExpnKind::Macro(MacroKind::Bang, name) => Some(name), + _ => None, + }) + .flatten(); + + Some((span, visible_macro)) +} + +/// Walks through the expansion ancestors of `original_span` to find a span that +/// is contained in `body_span` and has the same [`SyntaxContext`] as `body_span`. +/// The ancestor that was traversed just before the matching span (if any) is +/// also returned. +/// +/// For example, a return value of `Some((ancestor, Some(prev))` means that: +/// - `ancestor == original_span.find_ancestor_inside_same_ctxt(body_span)` +/// - `ancestor == prev.parent_callsite()` +/// +/// [`SyntaxContext`]: rustc_span::SyntaxContext +fn unexpand_into_body_span_with_prev( + original_span: Span, + body_span: Span, +) -> Option<(Span, Option)> { + let mut prev = None; + let mut curr = original_span; + + while !body_span.contains(curr) || !curr.eq_ctxt(body_span) { + prev = Some(curr); + curr = curr.parent_callsite()?; + } + + debug_assert_eq!(Some(curr), original_span.find_ancestor_in_same_ctxt(body_span)); + if let Some(prev) = prev { + debug_assert_eq!(Some(curr), prev.parent_callsite()); + } + + Some((curr, prev)) +} From ad575b093bee669258b1d4914bccf56c5b9d1e82 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 26 Jun 2024 11:34:31 +1000 Subject: [PATCH 06/12] Replace a magic boolean with enum `DeclareLetBindings` The new enum `DeclareLetBindings` has three variants: - `Yes`: Declare `let` bindings as normal, for `if` conditions. - `No`: Don't declare bindings, for match guards and let-else. - `LetNotPermitted`: Assert that `let` expressions should not occur. --- compiler/rustc_mir_build/src/build/block.rs | 3 +- .../rustc_mir_build/src/build/expr/into.rs | 5 +- .../rustc_mir_build/src/build/matches/mod.rs | 73 +++++++++++++++---- 3 files changed, 64 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index 476969a1bd7ad..4616018c3c690 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -1,3 +1,4 @@ +use crate::build::matches::DeclareLetBindings; use crate::build::ForGuard::OutsideGuard; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use rustc_middle::middle::region::Scope; @@ -213,7 +214,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pattern, None, initializer_span, - false, + DeclareLetBindings::No, true, ) }); diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 76bdc26a501a6..942c69b5c0a75 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -1,6 +1,7 @@ //! See docs in build/expr/mod.rs use crate::build::expr::category::{Category, RvalueFunc}; +use crate::build::matches::DeclareLetBindings; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, NeedsTemporary}; use rustc_ast::InlineAsmOptions; use rustc_data_structures::fx::FxHashMap; @@ -86,7 +87,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { cond, Some(condition_scope), // Temp scope source_info, - true, // Declare `let` bindings normally + DeclareLetBindings::Yes, // Declare `let` bindings normally )); // Lower the `then` arm into its block. @@ -163,7 +164,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info, // This flag controls how inner `let` expressions are lowered, // but either way there shouldn't be any of those in here. - true, + DeclareLetBindings::LetNotPermitted, ) }); let (short_circuit, continuation, constant) = match op { diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 6d52c30823769..71c065b3574c7 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -39,9 +39,27 @@ struct ThenElseArgs { /// `self.local_scope()` is used. temp_scope_override: Option, variable_source_info: SourceInfo, + /// Determines how bindings should be handled when lowering `let` expressions. + /// /// Forwarded to [`Builder::lower_let_expr`] when lowering [`ExprKind::Let`]. - /// When false (for match guards), `let` bindings won't be declared. - declare_let_bindings: bool, + declare_let_bindings: DeclareLetBindings, +} + +/// Should lowering a `let` expression also declare its bindings? +/// +/// Used by [`Builder::lower_let_expr`] when lowering [`ExprKind::Let`]. +#[derive(Clone, Copy)] +pub(crate) enum DeclareLetBindings { + /// Yes, declare `let` bindings as normal for `if` conditions. + Yes, + /// No, don't declare `let` bindings, because the caller declares them + /// separately due to special requirements. + /// + /// Used for match guards and let-else. + No, + /// Let expressions are not permitted in this context, so it is a bug to + /// try to lower one (e.g inside lazy-boolean-or or boolean-not). + LetNotPermitted, } impl<'a, 'tcx> Builder<'a, 'tcx> { @@ -57,7 +75,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr_id: ExprId, temp_scope_override: Option, variable_source_info: SourceInfo, - declare_let_bindings: bool, + declare_let_bindings: DeclareLetBindings, ) -> BlockAnd<()> { self.then_else_break_inner( block, @@ -91,13 +109,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.then_else_break_inner( block, lhs, - ThenElseArgs { declare_let_bindings: true, ..args }, + ThenElseArgs { + declare_let_bindings: DeclareLetBindings::LetNotPermitted, + ..args + }, ) }); let rhs_success_block = unpack!(this.then_else_break_inner( failure_block, rhs, - ThenElseArgs { declare_let_bindings: true, ..args }, + ThenElseArgs { + declare_let_bindings: DeclareLetBindings::LetNotPermitted, + ..args + }, )); // Make the LHS and RHS success arms converge to a common block. @@ -127,7 +151,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.then_else_break_inner( block, arg, - ThenElseArgs { declare_let_bindings: true, ..args }, + ThenElseArgs { + declare_let_bindings: DeclareLetBindings::LetNotPermitted, + ..args + }, ) }); this.break_for_else(success_block, args.variable_source_info); @@ -1991,8 +2018,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Pat binding - used for `let` and function parameters as well. impl<'a, 'tcx> Builder<'a, 'tcx> { - /// If the bindings have already been declared, set `declare_bindings` to - /// `false` to avoid duplicated bindings declaration; used for if-let guards. + /// Lowers a `let` expression that appears in a suitable context + /// (e.g. an `if` condition or match guard). + /// + /// Also used for lowering let-else statements, since they have similar + /// needs despite not actually using `let` expressions. + /// + /// Use [`DeclareLetBindings`] to control whether the `let` bindings are + /// declared or not. pub(crate) fn lower_let_expr( &mut self, mut block: BasicBlock, @@ -2000,7 +2033,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pat: &Pat<'tcx>, source_scope: Option, scope_span: Span, - declare_bindings: bool, + declare_let_bindings: DeclareLetBindings, storages_alive: bool, ) -> BlockAnd<()> { let expr_span = self.thir[expr_id].span; @@ -2017,10 +2050,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.break_for_else(otherwise_block, self.source_info(expr_span)); - if declare_bindings { - let expr_place = scrutinee.try_to_place(self); - let opt_expr_place = expr_place.as_ref().map(|place| (Some(place), expr_span)); - self.declare_bindings(source_scope, pat.span.to(scope_span), pat, None, opt_expr_place); + match declare_let_bindings { + DeclareLetBindings::Yes => { + let expr_place = scrutinee.try_to_place(self); + let opt_expr_place = expr_place.as_ref().map(|place| (Some(place), expr_span)); + self.declare_bindings( + source_scope, + pat.span.to(scope_span), + pat, + None, + opt_expr_place, + ); + } + DeclareLetBindings::No => {} // Caller is responsible for bindings. + DeclareLetBindings::LetNotPermitted => { + self.tcx.dcx().span_bug(expr_span, "let expression not expected in this context") + } } let success = self.bind_pattern( @@ -2203,7 +2248,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { guard, None, // Use `self.local_scope()` as the temp scope this.source_info(arm.span), - false, // For guards, `let` bindings are declared separately + DeclareLetBindings::No, // For guards, `let` bindings are declared separately ) }); From 3b22589cfa0015535ae08082b2cecf77ac1b5c33 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 26 Jun 2024 12:40:47 +1000 Subject: [PATCH 07/12] Replace a magic boolean with enum `EmitStorageLive` The previous boolean used `true` to indicate that storage-live should _not_ be emitted, so all occurrences of `Yes` and `No` should be the logical opposite of the previous value. --- compiler/rustc_mir_build/src/build/block.rs | 4 +- .../rustc_mir_build/src/build/matches/mod.rs | 47 ++++++++++++------- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index 4616018c3c690..80db30f0ae600 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -1,4 +1,4 @@ -use crate::build::matches::DeclareLetBindings; +use crate::build::matches::{DeclareLetBindings, EmitStorageLive}; use crate::build::ForGuard::OutsideGuard; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use rustc_middle::middle::region::Scope; @@ -215,7 +215,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { None, initializer_span, DeclareLetBindings::No, - true, + EmitStorageLive::No, ) }); matching.and(failure) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 71c065b3574c7..4827d2dbfa85c 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -62,6 +62,18 @@ pub(crate) enum DeclareLetBindings { LetNotPermitted, } +/// Used by [`Builder::bind_matched_candidate_for_arm_body`] to determine +/// whether or not to call [`Builder::storage_live_binding`] to emit +/// [`StatementKind::StorageLive`]. +#[derive(Clone, Copy)] +pub(crate) enum EmitStorageLive { + /// Yes, emit `StorageLive` as normal. + Yes, + /// No, don't emit `StorageLive`. The caller has taken responsibility for + /// emitting `StorageLive` as appropriate. + No, +} + impl<'a, 'tcx> Builder<'a, 'tcx> { /// Lowers a condition in a way that ensures that variables bound in any let /// expressions are definitely initialized in the if body. @@ -174,7 +186,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some(args.variable_source_info.scope), args.variable_source_info.span, args.declare_let_bindings, - false, + EmitStorageLive::Yes, ), _ => { let mut block = block; @@ -467,7 +479,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &fake_borrow_temps, scrutinee_span, Some((arm, match_scope)), - false, + EmitStorageLive::Yes, ); this.fixed_temps_scope = old_dedup_scope; @@ -512,7 +524,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fake_borrow_temps: &[(Place<'tcx>, Local, FakeBorrowKind)], scrutinee_span: Span, arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>, - storages_alive: bool, + emit_storage_live: EmitStorageLive, ) -> BasicBlock { if candidate.subcandidates.is_empty() { // Avoid generating another `BasicBlock` when we only have one @@ -524,7 +536,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { scrutinee_span, arm_match_scope, true, - storages_alive, + emit_storage_live, ) } else { // It's helpful to avoid scheduling drops multiple times to save @@ -561,7 +573,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { scrutinee_span, arm_match_scope, schedule_drops, - storages_alive, + emit_storage_live, ); if arm.is_none() { schedule_drops = false; @@ -731,7 +743,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &[], irrefutable_pat.span, None, - false, + EmitStorageLive::Yes, ) .unit() } @@ -807,6 +819,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + /// Emits a [`StatementKind::StorageLive`] for the given var, and also + /// schedules a drop if requested (and possible). pub(crate) fn storage_live_binding( &mut self, block: BasicBlock, @@ -2034,7 +2048,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_scope: Option, scope_span: Span, declare_let_bindings: DeclareLetBindings, - storages_alive: bool, + emit_storage_live: EmitStorageLive, ) -> BlockAnd<()> { let expr_span = self.thir[expr_id].span; let scrutinee = unpack!(block = self.lower_scrutinee(block, expr_id, expr_span)); @@ -2074,7 +2088,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &[], expr_span, None, - storages_alive, + emit_storage_live, ); // If branch coverage is enabled, record this branch. @@ -2099,7 +2113,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { scrutinee_span: Span, arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>, schedule_drops: bool, - storages_alive: bool, + emit_storage_live: EmitStorageLive, ) -> BasicBlock { debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate); @@ -2314,7 +2328,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { post_guard_block, true, by_value_bindings, - storages_alive, + emit_storage_live, ); post_guard_block @@ -2326,7 +2340,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, schedule_drops, bindings, - storages_alive, + emit_storage_live, ); block } @@ -2417,7 +2431,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block: BasicBlock, schedule_drops: bool, bindings: impl IntoIterator>, - storages_alive: bool, + emit_storage_live: EmitStorageLive, ) where 'tcx: 'b, { @@ -2427,19 +2441,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Assign each of the bindings. This may trigger moves out of the candidate. for binding in bindings { let source_info = self.source_info(binding.span); - let local = if storages_alive { + let local = match emit_storage_live { // Here storages are already alive, probably because this is a binding // from let-else. // We just need to schedule drop for the value. - self.var_local_id(binding.var_id, OutsideGuard).into() - } else { - self.storage_live_binding( + EmitStorageLive::No => self.var_local_id(binding.var_id, OutsideGuard).into(), + EmitStorageLive::Yes => self.storage_live_binding( block, binding.var_id, binding.span, OutsideGuard, schedule_drops, - ) + ), }; if schedule_drops { self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard); From ed07712e96506ca827ced41d748550b99318d47f Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 26 Jun 2024 13:44:25 +1000 Subject: [PATCH 08/12] Replace a magic boolean with enum `ScheduleDrops` --- compiler/rustc_mir_build/src/build/block.rs | 18 +++++- .../rustc_mir_build/src/build/matches/mod.rs | 56 ++++++++++++++----- 2 files changed, 56 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index 80db30f0ae600..5ccbd7c59cfba 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -1,4 +1,4 @@ -use crate::build::matches::{DeclareLetBindings, EmitStorageLive}; +use crate::build::matches::{DeclareLetBindings, EmitStorageLive, ScheduleDrops}; use crate::build::ForGuard::OutsideGuard; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; use rustc_middle::middle::region::Scope; @@ -202,7 +202,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pattern, UserTypeProjections::none(), &mut |this, _, _, node, span, _, _| { - this.storage_live_binding(block, node, span, OutsideGuard, true); + this.storage_live_binding( + block, + node, + span, + OutsideGuard, + ScheduleDrops::Yes, + ); }, ); let else_block_span = this.thir[*else_block].span; @@ -292,7 +298,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { pattern, UserTypeProjections::none(), &mut |this, _, _, node, span, _, _| { - this.storage_live_binding(block, node, span, OutsideGuard, true); + this.storage_live_binding( + block, + node, + span, + OutsideGuard, + ScheduleDrops::Yes, + ); this.schedule_drop_for_binding(node, span, OutsideGuard); }, ) diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 4827d2dbfa85c..efed52231e3fa 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -28,6 +28,7 @@ mod simplify; mod test; mod util; +use std::assert_matches::assert_matches; use std::borrow::Borrow; use std::mem; @@ -74,6 +75,17 @@ pub(crate) enum EmitStorageLive { No, } +/// Used by [`Builder::storage_live_binding`] and [`Builder::bind_matched_candidate_for_arm_body`] +/// to decide whether to schedule drops. +#[derive(Clone, Copy, Debug)] +pub(crate) enum ScheduleDrops { + /// Yes, the relevant functions should also schedule drops as appropriate. + Yes, + /// No, don't schedule drops. The caller has taken responsibility for any + /// appropriate drops. + No, +} + impl<'a, 'tcx> Builder<'a, 'tcx> { /// Lowers a condition in a way that ensures that variables bound in any let /// expressions are definitely initialized in the if body. @@ -535,7 +547,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fake_borrow_temps, scrutinee_span, arm_match_scope, - true, + ScheduleDrops::Yes, emit_storage_live, ) } else { @@ -554,7 +566,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // To handle this we instead unschedule it's drop after each time // we lower the guard. let target_block = self.cfg.start_new_block(); - let mut schedule_drops = true; + let mut schedule_drops = ScheduleDrops::Yes; let arm = arm_match_scope.unzip().0; // We keep a stack of all of the bindings and type ascriptions // from the parent candidates that we visit, that also need to @@ -576,7 +588,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { emit_storage_live, ); if arm.is_none() { - schedule_drops = false; + schedule_drops = ScheduleDrops::No; } self.cfg.goto(binding_end, outer_source_info, target_block); }, @@ -602,8 +614,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match irrefutable_pat.kind { // Optimize the case of `let x = ...` to write directly into `x` PatKind::Binding { mode: BindingMode(ByRef::No, _), var, subpattern: None, .. } => { - let place = - self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); + let place = self.storage_live_binding( + block, + var, + irrefutable_pat.span, + OutsideGuard, + ScheduleDrops::Yes, + ); unpack!(block = self.expr_into_dest(place, block, initializer_id)); // Inject a fake read, see comments on `FakeReadCause::ForLet`. @@ -636,8 +653,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }, ascription: thir::Ascription { ref annotation, variance: _ }, } => { - let place = - self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); + let place = self.storage_live_binding( + block, + var, + irrefutable_pat.span, + OutsideGuard, + ScheduleDrops::Yes, + ); unpack!(block = self.expr_into_dest(place, block, initializer_id)); // Inject a fake read, see comments on `FakeReadCause::ForLet`. @@ -827,7 +849,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { var: LocalVarId, span: Span, for_guard: ForGuard, - schedule_drop: bool, + schedule_drop: ScheduleDrops, ) -> Place<'tcx> { let local_id = self.var_local_id(var, for_guard); let source_info = self.source_info(span); @@ -835,7 +857,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Although there is almost always scope for given variable in corner cases // like #92893 we might get variable with no scope. if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) - && schedule_drop + && matches!(schedule_drop, ScheduleDrops::Yes) { self.schedule_drop(span, region_scope, local_id, DropKind::Storage); } @@ -2112,7 +2134,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fake_borrows: &[(Place<'tcx>, Local, FakeBorrowKind)], scrutinee_span: Span, arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>, - schedule_drops: bool, + schedule_drops: ScheduleDrops, emit_storage_live: EmitStorageLive, ) -> BasicBlock { debug!("bind_and_guard_matched_candidate(candidate={:?})", candidate); @@ -2323,10 +2345,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let cause = FakeReadCause::ForGuardBinding; self.cfg.push_fake_read(post_guard_block, guard_end, cause, Place::from(local_id)); } - assert!(schedule_drops, "patterns with guards must schedule drops"); + assert_matches!( + schedule_drops, + ScheduleDrops::Yes, + "patterns with guards must schedule drops" + ); self.bind_matched_candidate_for_arm_body( post_guard_block, - true, + ScheduleDrops::Yes, by_value_bindings, emit_storage_live, ); @@ -2376,7 +2402,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn bind_matched_candidate_for_guard<'b>( &mut self, block: BasicBlock, - schedule_drops: bool, + schedule_drops: ScheduleDrops, bindings: impl IntoIterator>, ) where 'tcx: 'b, @@ -2429,7 +2455,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn bind_matched_candidate_for_arm_body<'b>( &mut self, block: BasicBlock, - schedule_drops: bool, + schedule_drops: ScheduleDrops, bindings: impl IntoIterator>, emit_storage_live: EmitStorageLive, ) where @@ -2454,7 +2480,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { schedule_drops, ), }; - if schedule_drops { + if matches!(schedule_drops, ScheduleDrops::Yes) { self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard); } let rvalue = match binding.binding_mode.0 { From 6c3314905574651fa2e004173187bd5d202f0df1 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 30 Jun 2024 18:20:45 +1000 Subject: [PATCH 09/12] coverage: Avoid getting extra unexpansion info when we don't need it These particular callers don't actually use the returned macro information, so they can use a simpler span-unexpansion function that doesn't return it. --- .../src/coverage/mappings.rs | 9 +++--- .../src/coverage/unexpand.rs | 28 +++++++++++-------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index e003de4e1fd71..235992ac5470d 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -10,7 +10,7 @@ use rustc_span::Span; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, START_BCB}; use crate::coverage::spans::extract_refined_covspans; -use crate::coverage::unexpand::unexpand_into_body_span_with_visible_macro; +use crate::coverage::unexpand::unexpand_into_body_span; use crate::coverage::ExtractedHirInfo; /// Associates an ordinary executable code span with its corresponding BCB. @@ -201,8 +201,7 @@ pub(super) fn extract_branch_pairs( if !raw_span.ctxt().outer_expn_data().is_root() { return None; } - let (span, _) = - unexpand_into_body_span_with_visible_macro(raw_span, hir_info.body_span)?; + let span = unexpand_into_body_span(raw_span, hir_info.body_span)?; let bcb_from_marker = |marker: BlockMarkerId| basic_coverage_blocks.bcb_from_bb(block_markers[marker]?); @@ -237,7 +236,7 @@ pub(super) fn extract_mcdc_mappings( if !raw_span.ctxt().outer_expn_data().is_root() { return None; } - let (span, _) = unexpand_into_body_span_with_visible_macro(raw_span, body_span)?; + let span = unexpand_into_body_span(raw_span, body_span)?; let true_bcb = bcb_from_marker(true_marker)?; let false_bcb = bcb_from_marker(false_marker)?; @@ -260,7 +259,7 @@ pub(super) fn extract_mcdc_mappings( mcdc_decisions.extend(branch_info.mcdc_decision_spans.iter().filter_map( |decision: &mir::coverage::MCDCDecisionSpan| { - let (span, _) = unexpand_into_body_span_with_visible_macro(decision.span, body_span)?; + let span = unexpand_into_body_span(decision.span, body_span)?; let end_bcbs = decision .end_markers diff --git a/compiler/rustc_mir_transform/src/coverage/unexpand.rs b/compiler/rustc_mir_transform/src/coverage/unexpand.rs index 18532b8ee4581..8cde291b9073e 100644 --- a/compiler/rustc_mir_transform/src/coverage/unexpand.rs +++ b/compiler/rustc_mir_transform/src/coverage/unexpand.rs @@ -1,12 +1,18 @@ use rustc_span::{ExpnKind, MacroKind, Span, Symbol}; -/// Returns an extrapolated span (pre-expansion[^1]) corresponding to a range -/// within the function's body source. This span is guaranteed to be contained -/// within, or equal to, the `body_span`. If the extrapolated span is not -/// contained within the `body_span`, `None` is returned. +/// Walks through the expansion ancestors of `original_span` to find a span that +/// is contained in `body_span` and has the same [syntax context] as `body_span`. +pub(crate) fn unexpand_into_body_span(original_span: Span, body_span: Span) -> Option { + // Because we don't need to return any extra ancestor information, + // we can just delegate directly to `find_ancestor_inside_same_ctxt`. + original_span.find_ancestor_inside_same_ctxt(body_span) +} + +/// Walks through the expansion ancestors of `original_span` to find a span that +/// is contained in `body_span` and has the same [syntax context] as `body_span`. /// -/// [^1]Expansions result from Rust syntax including macros, syntactic sugar, -/// etc.). +/// If the returned span represents a bang-macro invocation (e.g. `foo!(..)`), +/// the returned symbol will be the name of that macro (e.g. `foo`). pub(crate) fn unexpand_into_body_span_with_visible_macro( original_span: Span, body_span: Span, @@ -24,15 +30,15 @@ pub(crate) fn unexpand_into_body_span_with_visible_macro( } /// Walks through the expansion ancestors of `original_span` to find a span that -/// is contained in `body_span` and has the same [`SyntaxContext`] as `body_span`. +/// is contained in `body_span` and has the same [syntax context] as `body_span`. /// The ancestor that was traversed just before the matching span (if any) is /// also returned. /// -/// For example, a return value of `Some((ancestor, Some(prev))` means that: +/// For example, a return value of `Some((ancestor, Some(prev)))` means that: /// - `ancestor == original_span.find_ancestor_inside_same_ctxt(body_span)` -/// - `ancestor == prev.parent_callsite()` +/// - `prev.parent_callsite() == ancestor` /// -/// [`SyntaxContext`]: rustc_span::SyntaxContext +/// [syntax context]: rustc_span::SyntaxContext fn unexpand_into_body_span_with_prev( original_span: Span, body_span: Span, @@ -45,7 +51,7 @@ fn unexpand_into_body_span_with_prev( curr = curr.parent_callsite()?; } - debug_assert_eq!(Some(curr), original_span.find_ancestor_in_same_ctxt(body_span)); + debug_assert_eq!(Some(curr), original_span.find_ancestor_inside_same_ctxt(body_span)); if let Some(prev) = prev { debug_assert_eq!(Some(curr), prev.parent_callsite()); } From 4b516f599b15c81a5ab26c0044b9fdf84cf5e3c3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 30 Jun 2024 12:40:24 +0200 Subject: [PATCH 10/12] Improve `run-make-support` library `args` API --- src/tools/run-make-support/src/lib.rs | 5 +++-- tests/run-make/arguments-non-c-like-enum/rmake.rs | 4 ++-- tests/run-make/c-link-to-rust-staticlib/rmake.rs | 2 +- tests/run-make/c-link-to-rust-va-list-fn/rmake.rs | 2 +- tests/run-make/glibc-staticlib-args/rmake.rs | 4 ++-- tests/run-make/print-check-cfg/rmake.rs | 8 ++------ tests/run-make/return-non-c-like-enum/rmake.rs | 4 ++-- tests/run-make/textrel-on-minimal-lib/rmake.rs | 4 ++-- 8 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 31b913810b665..df417722e024f 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -525,11 +525,12 @@ macro_rules! impl_common_helpers { /// Generic command arguments provider. Prefer specific helper methods if possible. /// Note that for some executables, arguments might be platform specific. For C/C++ /// compilers, arguments might be platform *and* compiler specific. - pub fn args(&mut self, args: &[S]) -> &mut Self + pub fn args(&mut self, args: V) -> &mut Self where + V: AsRef<[S]>, S: AsRef<::std::ffi::OsStr>, { - self.cmd.args(args); + self.cmd.args(args.as_ref()); self } diff --git a/tests/run-make/arguments-non-c-like-enum/rmake.rs b/tests/run-make/arguments-non-c-like-enum/rmake.rs index 88f4d664aa626..036691e850931 100644 --- a/tests/run-make/arguments-non-c-like-enum/rmake.rs +++ b/tests/run-make/arguments-non-c-like-enum/rmake.rs @@ -10,8 +10,8 @@ pub fn main() { cc().input("test.c") .input(static_lib_name("nonclike")) .out_exe("test") - .args(&extra_c_flags()) - .args(&extra_cxx_flags()) + .args(extra_c_flags()) + .args(extra_cxx_flags()) .inspect(|cmd| eprintln!("{cmd:?}")) .run(); run("test"); diff --git a/tests/run-make/c-link-to-rust-staticlib/rmake.rs b/tests/run-make/c-link-to-rust-staticlib/rmake.rs index 2edd36b9ec0b7..d60b37524f43c 100644 --- a/tests/run-make/c-link-to-rust-staticlib/rmake.rs +++ b/tests/run-make/c-link-to-rust-staticlib/rmake.rs @@ -9,7 +9,7 @@ use std::fs; fn main() { rustc().input("foo.rs").run(); - cc().input("bar.c").input(static_lib_name("foo")).out_exe("bar").args(&extra_c_flags()).run(); + cc().input("bar.c").input(static_lib_name("foo")).out_exe("bar").args(extra_c_flags()).run(); run("bar"); remove_file(static_lib_name("foo")); run("bar"); diff --git a/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs b/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs index a01e259bce010..63904bea6227b 100644 --- a/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs +++ b/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs @@ -12,7 +12,7 @@ fn main() { cc().input("test.c") .input(static_lib_name("checkrust")) .out_exe("test") - .args(&extra_c_flags()) + .args(extra_c_flags()) .run(); run("test"); } diff --git a/tests/run-make/glibc-staticlib-args/rmake.rs b/tests/run-make/glibc-staticlib-args/rmake.rs index 8ab10419ab9d3..fc13be538123b 100644 --- a/tests/run-make/glibc-staticlib-args/rmake.rs +++ b/tests/run-make/glibc-staticlib-args/rmake.rs @@ -11,8 +11,8 @@ fn main() { cc().input("program.c") .arg(static_lib_name("library")) .out_exe("program") - .args(&extra_c_flags()) - .args(&extra_cxx_flags()) + .args(extra_c_flags()) + .args(extra_cxx_flags()) .run(); run(&bin_name("program")); } diff --git a/tests/run-make/print-check-cfg/rmake.rs b/tests/run-make/print-check-cfg/rmake.rs index f4b02b5e265be..4a79910c8e05e 100644 --- a/tests/run-make/print-check-cfg/rmake.rs +++ b/tests/run-make/print-check-cfg/rmake.rs @@ -86,12 +86,8 @@ fn main() { } fn check(CheckCfg { args, contains }: CheckCfg) { - let output = rustc() - .input("lib.rs") - .arg("-Zunstable-options") - .arg("--print=check-cfg") - .args(&*args) - .run(); + let output = + rustc().input("lib.rs").arg("-Zunstable-options").arg("--print=check-cfg").args(args).run(); let stdout = output.stdout_utf8(); diff --git a/tests/run-make/return-non-c-like-enum/rmake.rs b/tests/run-make/return-non-c-like-enum/rmake.rs index e698790b43c06..ecdfbd8889941 100644 --- a/tests/run-make/return-non-c-like-enum/rmake.rs +++ b/tests/run-make/return-non-c-like-enum/rmake.rs @@ -11,8 +11,8 @@ fn main() { cc().input("test.c") .arg(&static_lib_name("nonclike")) .out_exe("test") - .args(&extra_c_flags()) - .args(&extra_cxx_flags()) + .args(extra_c_flags()) + .args(extra_cxx_flags()) .run(); run("test"); } diff --git a/tests/run-make/textrel-on-minimal-lib/rmake.rs b/tests/run-make/textrel-on-minimal-lib/rmake.rs index eba664479f112..625ded70ad624 100644 --- a/tests/run-make/textrel-on-minimal-lib/rmake.rs +++ b/tests/run-make/textrel-on-minimal-lib/rmake.rs @@ -20,8 +20,8 @@ fn main() { .out_exe(&dynamic_lib_name("bar")) .arg("-fPIC") .arg("-shared") - .args(&extra_c_flags()) - .args(&extra_cxx_flags()) + .args(extra_c_flags()) + .args(extra_cxx_flags()) .run(); llvm_readobj() .input(dynamic_lib_name("bar")) From 8a0e1ab565346491f932612508e57c225ddbb34c Mon Sep 17 00:00:00 2001 From: Michael Baikov Date: Sun, 30 Jun 2024 07:12:26 -0400 Subject: [PATCH 11/12] Add a regression test for #123630 compiler should not suggest nonsensical signatures, original suggestion was error[E0308]: mismatched types --> src/lib.rs:3:31 | 3 | fn select(filter: F) -> Select { | ------ ^^^^^^^^^^^^ expected `Select`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression | = note: expected struct `Select` found unit type `()` error[E0282]: type annotations needed for `Select<{closure@src/lib.rs:8:22: 8:25}, I>` --> src/lib.rs:8:9 | 8 | let lit = select(|x| match x { | ^^^ | help: consider giving `lit` an explicit type, where the type for type parameter `I` is specified | 8 | let lit: Select<{closure@src/lib.rs:8:22: 8:25}, I> = select(|x| match x { | ++++++++++++++++++++++++++++++++++++++++++++ Some errors have detailed explanations: E0282, E0308. For more information about an error, try `rustc --explain E0282`. --- .../types/dont-suggest-path-names.rs | 17 ++++++++++++ .../types/dont-suggest-path-names.stderr | 26 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 tests/ui/suggestions/types/dont-suggest-path-names.rs create mode 100644 tests/ui/suggestions/types/dont-suggest-path-names.stderr diff --git a/tests/ui/suggestions/types/dont-suggest-path-names.rs b/tests/ui/suggestions/types/dont-suggest-path-names.rs new file mode 100644 index 0000000000000..d160e49cd0358 --- /dev/null +++ b/tests/ui/suggestions/types/dont-suggest-path-names.rs @@ -0,0 +1,17 @@ +// This is a regression test for #123630 +// +// Prior to #123703 this was resulting in compiler suggesting add a type signature +// for `lit` containing path to a file containing `Select` - something obviously invalid. + +struct Select(F, I); +fn select(filter: F) -> Select {} +//~^ 7:31: 7:43: mismatched types [E0308] + +fn parser1() { + let lit = select(|x| match x { + //~^ 11:23: 11:24: type annotations needed [E0282] + _ => (), + }); +} + +fn main() {} diff --git a/tests/ui/suggestions/types/dont-suggest-path-names.stderr b/tests/ui/suggestions/types/dont-suggest-path-names.stderr new file mode 100644 index 0000000000000..5c71e350f81a3 --- /dev/null +++ b/tests/ui/suggestions/types/dont-suggest-path-names.stderr @@ -0,0 +1,26 @@ +error[E0308]: mismatched types + --> $DIR/dont-suggest-path-names.rs:7:31 + | +LL | fn select(filter: F) -> Select {} + | ------ ^^^^^^^^^^^^ expected `Select`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + | + = note: expected struct `Select` + found unit type `()` + +error[E0282]: type annotations needed + --> $DIR/dont-suggest-path-names.rs:11:23 + | +LL | let lit = select(|x| match x { + | ^ - type must be known at this point + | +help: consider giving this closure parameter an explicit type + | +LL | let lit = select(|x: /* Type */| match x { + | ++++++++++++ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0282, E0308. +For more information about an error, try `rustc --explain E0282`. From f79bf19a7a9dc9bbdab3d1c274bd267b0e86a66e Mon Sep 17 00:00:00 2001 From: Boxy Date: Sun, 30 Jun 2024 15:15:05 +0100 Subject: [PATCH 12/12] Update test comment --- .../repeat_expr_hack_gives_right_generics.rs | 22 +++++++++++-------- ...peat_expr_hack_gives_right_generics.stderr | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.rs b/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.rs index 899db191ae7d7..e7ae2ea1d5a6a 100644 --- a/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.rs +++ b/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.rs @@ -1,14 +1,18 @@ -// Given an anon const `a`: `{ N }` and some anon const `b` which references the -// first anon const: `{ [1; a] }`. `b` should not have any generics as it is not -// a simple `N` argument nor is it a repeat expr count. +// Given a const argument `a`: `{ N }` and some const argument `b` which references the +// first anon const like so: `{ [1; a] }`. The `b` anon const should not be allowed to use +// any generic parameters as: +// - The anon const is not a simple bare parameter, e.g. `N` +// - The anon const is not the *length* of an array repeat expression, e.g. the `N` in `[1; N]`. // -// On the other hand `b` *is* a repeat expr count and so it should inherit its -// parents generics as part of the `const_evaluatable_unchecked` fcw (#76200). +// On the other hand `a` *is* a const argument for the length of a repeat expression and +// so it *should* inherit the generics declared on its parent definition. (This hack is +// introduced for backwards compatibility and is tracked in #76200) // -// In this specific case however `b`'s parent should be `a` and so it should wind -// up not having any generics after all. If `a` were to inherit its generics from -// the enclosing item then the reference to `a` from `b` would contain generic -// parameters not usable by `b` which would cause us to ICE. +// In this specific case `a`'s parent should be `b` which does not have any generics. +// This means that even though `a` inherits generics from `b`, it still winds up not having +// access to any generic parameters. If `a` were to inherit its generics from the surrounding +// function `foo` then the reference to `a` from `b` would contain generic parameters not usable +// by `b` which would cause us to ICE. fn bar() {} diff --git a/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.stderr b/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.stderr index 64548cc5a301e..72a6e6977f583 100644 --- a/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.stderr +++ b/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.stderr @@ -1,5 +1,5 @@ error: generic parameters may not be used in const operations - --> $DIR/repeat_expr_hack_gives_right_generics.rs:16:17 + --> $DIR/repeat_expr_hack_gives_right_generics.rs:20:17 | LL | bar::<{ [1; N] }>(); | ^ cannot perform const operation using `N`