diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/codegen/intrinsics/carrying_mul_add.rs | 137 | ||||
| -rw-r--r-- | tests/run-make/branch-protection-check-IBT/Makefile | 21 | ||||
| -rw-r--r-- | tests/run-make/branch-protection-check-IBT/_rmake.rs | 29 | ||||
| -rw-r--r-- | tests/run-make/branch-protection-check-IBT/main.rs | 8 | ||||
| -rw-r--r-- | tests/run-make/branch-protection-check-IBT/rmake.rs | 53 | ||||
| -rw-r--r-- | tests/run-make/libs-through-symlinks/Makefile | 22 | ||||
| -rw-r--r-- | tests/run-make/libs-through-symlinks/rmake.rs | 48 | ||||
| -rw-r--r-- | tests/ui-fulldeps/pprust-parenthesis-insertion.rs | 7 | ||||
| -rw-r--r-- | tests/ui/consts/error-is-freeze.rs | 14 | ||||
| -rw-r--r-- | tests/ui/consts/error-is-freeze.stderr | 14 | ||||
| -rw-r--r-- | tests/ui/impl-trait/auto-trait-contains-err.rs (renamed from tests/crashes/131050.rs) | 4 | ||||
| -rw-r--r-- | tests/ui/impl-trait/auto-trait-contains-err.stderr | 11 | ||||
| -rw-r--r-- | tests/ui/structs/manual-default-impl-could-be-derived.rs | 194 | ||||
| -rw-r--r-- | tests/ui/structs/manual-default-impl-could-be-derived.stderr | 144 |
14 files changed, 630 insertions, 76 deletions
diff --git a/tests/codegen/intrinsics/carrying_mul_add.rs b/tests/codegen/intrinsics/carrying_mul_add.rs new file mode 100644 index 00000000000..174c4077f09 --- /dev/null +++ b/tests/codegen/intrinsics/carrying_mul_add.rs @@ -0,0 +1,137 @@ +//@ revisions: RAW OPT +//@ compile-flags: -C opt-level=1 +//@[RAW] compile-flags: -C no-prepopulate-passes +//@[OPT] min-llvm-version: 19 + +#![crate_type = "lib"] +#![feature(core_intrinsics)] +#![feature(core_intrinsics_fallbacks)] + +// Note that LLVM seems to sometimes permute the order of arguments to mul and add, +// so these tests don't check the arguments in the optimized revision. + +use std::intrinsics::{carrying_mul_add, fallback}; + +// The fallbacks are emitted even when they're never used, but optimize out. + +// RAW: wide_mul_u128 +// OPT-NOT: wide_mul_u128 + +// CHECK-LABEL: @cma_u8 +#[no_mangle] +pub unsafe fn cma_u8(a: u8, b: u8, c: u8, d: u8) -> (u8, u8) { + // CHECK: [[A:%.+]] = zext i8 %a to i16 + // CHECK: [[B:%.+]] = zext i8 %b to i16 + // CHECK: [[C:%.+]] = zext i8 %c to i16 + // CHECK: [[D:%.+]] = zext i8 %d to i16 + // CHECK: [[AB:%.+]] = mul nuw i16 + // RAW-SAME: [[A]], [[B]] + // CHECK: [[ABC:%.+]] = add nuw i16 + // RAW-SAME: [[AB]], [[C]] + // CHECK: [[ABCD:%.+]] = add nuw i16 + // RAW-SAME: [[ABC]], [[D]] + // CHECK: [[LOW:%.+]] = trunc i16 [[ABCD]] to i8 + // CHECK: [[HIGHW:%.+]] = lshr i16 [[ABCD]], 8 + // RAW: [[HIGH:%.+]] = trunc i16 [[HIGHW]] to i8 + // OPT: [[HIGH:%.+]] = trunc nuw i16 [[HIGHW]] to i8 + // CHECK: [[PAIR0:%.+]] = insertvalue { i8, i8 } poison, i8 [[LOW]], 0 + // CHECK: [[PAIR1:%.+]] = insertvalue { i8, i8 } [[PAIR0]], i8 [[HIGH]], 1 + // OPT: ret { i8, i8 } [[PAIR1]] + carrying_mul_add(a, b, c, d) +} + +// CHECK-LABEL: @cma_u32 +#[no_mangle] +pub unsafe fn cma_u32(a: u32, b: u32, c: u32, d: u32) -> (u32, u32) { + // CHECK: [[A:%.+]] = zext i32 %a to i64 + // CHECK: [[B:%.+]] = zext i32 %b to i64 + // CHECK: [[C:%.+]] = zext i32 %c to i64 + // CHECK: [[D:%.+]] = zext i32 %d to i64 + // CHECK: [[AB:%.+]] = mul nuw i64 + // RAW-SAME: [[A]], [[B]] + // CHECK: [[ABC:%.+]] = add nuw i64 + // RAW-SAME: [[AB]], [[C]] + // CHECK: [[ABCD:%.+]] = add nuw i64 + // RAW-SAME: [[ABC]], [[D]] + // CHECK: [[LOW:%.+]] = trunc i64 [[ABCD]] to i32 + // CHECK: [[HIGHW:%.+]] = lshr i64 [[ABCD]], 32 + // RAW: [[HIGH:%.+]] = trunc i64 [[HIGHW]] to i32 + // OPT: [[HIGH:%.+]] = trunc nuw i64 [[HIGHW]] to i32 + // CHECK: [[PAIR0:%.+]] = insertvalue { i32, i32 } poison, i32 [[LOW]], 0 + // CHECK: [[PAIR1:%.+]] = insertvalue { i32, i32 } [[PAIR0]], i32 [[HIGH]], 1 + // OPT: ret { i32, i32 } [[PAIR1]] + carrying_mul_add(a, b, c, d) +} + +// CHECK-LABEL: @cma_u128 +// CHECK-SAME: sret{{.+}}dereferenceable(32){{.+}}%_0,{{.+}}%a,{{.+}}%b,{{.+}}%c,{{.+}}%d +#[no_mangle] +pub unsafe fn cma_u128(a: u128, b: u128, c: u128, d: u128) -> (u128, u128) { + // CHECK: [[A:%.+]] = zext i128 %a to i256 + // CHECK: [[B:%.+]] = zext i128 %b to i256 + // CHECK: [[C:%.+]] = zext i128 %c to i256 + // CHECK: [[D:%.+]] = zext i128 %d to i256 + // CHECK: [[AB:%.+]] = mul nuw i256 + // RAW-SAME: [[A]], [[B]] + // CHECK: [[ABC:%.+]] = add nuw i256 + // RAW-SAME: [[AB]], [[C]] + // CHECK: [[ABCD:%.+]] = add nuw i256 + // RAW-SAME: [[ABC]], [[D]] + // CHECK: [[LOW:%.+]] = trunc i256 [[ABCD]] to i128 + // CHECK: [[HIGHW:%.+]] = lshr i256 [[ABCD]], 128 + // RAW: [[HIGH:%.+]] = trunc i256 [[HIGHW]] to i128 + // OPT: [[HIGH:%.+]] = trunc nuw i256 [[HIGHW]] to i128 + // RAW: [[PAIR0:%.+]] = insertvalue { i128, i128 } poison, i128 [[LOW]], 0 + // RAW: [[PAIR1:%.+]] = insertvalue { i128, i128 } [[PAIR0]], i128 [[HIGH]], 1 + // OPT: store i128 [[LOW]], ptr %_0 + // OPT: [[P1:%.+]] = getelementptr inbounds i8, ptr %_0, {{i32|i64}} 16 + // OPT: store i128 [[HIGH]], ptr [[P1]] + // CHECK: ret void + carrying_mul_add(a, b, c, d) +} + +// CHECK-LABEL: @cma_i128 +// CHECK-SAME: sret{{.+}}dereferenceable(32){{.+}}%_0,{{.+}}%a,{{.+}}%b,{{.+}}%c,{{.+}}%d +#[no_mangle] +pub unsafe fn cma_i128(a: i128, b: i128, c: i128, d: i128) -> (u128, i128) { + // CHECK: [[A:%.+]] = sext i128 %a to i256 + // CHECK: [[B:%.+]] = sext i128 %b to i256 + // CHECK: [[C:%.+]] = sext i128 %c to i256 + // CHECK: [[D:%.+]] = sext i128 %d to i256 + // CHECK: [[AB:%.+]] = mul nsw i256 + // RAW-SAME: [[A]], [[B]] + // CHECK: [[ABC:%.+]] = add nsw i256 + // RAW-SAME: [[AB]], [[C]] + // CHECK: [[ABCD:%.+]] = add nsw i256 + // RAW-SAME: [[ABC]], [[D]] + // CHECK: [[LOW:%.+]] = trunc i256 [[ABCD]] to i128 + // CHECK: [[HIGHW:%.+]] = lshr i256 [[ABCD]], 128 + // RAW: [[HIGH:%.+]] = trunc i256 [[HIGHW]] to i128 + // OPT: [[HIGH:%.+]] = trunc nuw i256 [[HIGHW]] to i128 + // RAW: [[PAIR0:%.+]] = insertvalue { i128, i128 } poison, i128 [[LOW]], 0 + // RAW: [[PAIR1:%.+]] = insertvalue { i128, i128 } [[PAIR0]], i128 [[HIGH]], 1 + // OPT: store i128 [[LOW]], ptr %_0 + // OPT: [[P1:%.+]] = getelementptr inbounds i8, ptr %_0, {{i32|i64}} 16 + // OPT: store i128 [[HIGH]], ptr [[P1]] + // CHECK: ret void + carrying_mul_add(a, b, c, d) +} + +// CHECK-LABEL: @fallback_cma_u32 +#[no_mangle] +pub unsafe fn fallback_cma_u32(a: u32, b: u32, c: u32, d: u32) -> (u32, u32) { + // OPT-DAG: [[A:%.+]] = zext i32 %a to i64 + // OPT-DAG: [[B:%.+]] = zext i32 %b to i64 + // OPT-DAG: [[AB:%.+]] = mul nuw i64 + // OPT-DAG: [[C:%.+]] = zext i32 %c to i64 + // OPT-DAG: [[ABC:%.+]] = add nuw i64{{.+}}[[C]] + // OPT-DAG: [[D:%.+]] = zext i32 %d to i64 + // OPT-DAG: [[ABCD:%.+]] = add nuw i64{{.+}}[[D]] + // OPT-DAG: [[LOW:%.+]] = trunc i64 [[ABCD]] to i32 + // OPT-DAG: [[HIGHW:%.+]] = lshr i64 [[ABCD]], 32 + // OPT-DAG: [[HIGH:%.+]] = trunc nuw i64 [[HIGHW]] to i32 + // OPT-DAG: [[PAIR0:%.+]] = insertvalue { i32, i32 } poison, i32 [[LOW]], 0 + // OPT-DAG: [[PAIR1:%.+]] = insertvalue { i32, i32 } [[PAIR0]], i32 [[HIGH]], 1 + // OPT-DAG: ret { i32, i32 } [[PAIR1]] + fallback::CarryingMulAdd::carrying_mul_add(a, b, c, d) +} diff --git a/tests/run-make/branch-protection-check-IBT/Makefile b/tests/run-make/branch-protection-check-IBT/Makefile deleted file mode 100644 index ee0e034627f..00000000000 --- a/tests/run-make/branch-protection-check-IBT/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# Check for GNU Property Note - -include ../tools.mk - -# How to run this -# python3 x.py test --target x86_64-unknown-linux-gnu tests/run-make/branch-protection-check-IBT/ - -# only-x86_64 - -# ignore-test -# FIXME(jieyouxu): This test never runs because the `ifeq` check on line 17 -# compares `x86` to `x86_64`, which always evaluates to false. -# When the test does run, the compilation does not include `.note.gnu.property`. -# See https://github.com/rust-lang/rust/pull/126720 for more information. - -all: -ifeq ($(filter x86,$(LLVM_COMPONENTS)),x86_64) - $(RUSTC) --target x86_64-unknown-linux-gnu -Z cf-protection=branch -L$(TMPDIR) -C link-args='-nostartfiles' -C save-temps ./main.rs -o $(TMPDIR)/rsmain - readelf -nW $(TMPDIR)/rsmain | $(CGREP) -e ".note.gnu.property" -endif - diff --git a/tests/run-make/branch-protection-check-IBT/_rmake.rs b/tests/run-make/branch-protection-check-IBT/_rmake.rs deleted file mode 100644 index 91151408785..00000000000 --- a/tests/run-make/branch-protection-check-IBT/_rmake.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Check for GNU Property Note - -// How to run this -// python3 x.py test --target x86_64-unknown-linux-gnu tests/run-make/branch-protection-check-IBT/ - -//@ only-x86_64 - -//@ ignore-test -// FIXME(jieyouxu): see the FIXME in the Makefile - -use run_make_support::{cwd, env_var, llvm_readobj, rustc}; - -fn main() { - let llvm_components = env_var("LLVM_COMPONENTS"); - if !format!(" {llvm_components} ").contains(" x86 ") { - return; - } - - rustc() - .input("main.rs") - .target("x86_64-unknown-linux-gnu") - .arg("-Zcf-protection=branch") - .arg(format!("-L{}", cwd().display())) - .arg("-Clink-args=-nostartfiles") - .arg("-Csave-temps") - .run(); - - llvm_readobj().arg("-nW").input("main").run().assert_stdout_contains(".note.gnu.property"); -} diff --git a/tests/run-make/branch-protection-check-IBT/main.rs b/tests/run-make/branch-protection-check-IBT/main.rs index ad379d6ea43..445b8795134 100644 --- a/tests/run-make/branch-protection-check-IBT/main.rs +++ b/tests/run-make/branch-protection-check-IBT/main.rs @@ -1,3 +1,5 @@ -fn main() { - println!("hello world"); -} +#![feature(no_core)] +#![allow(internal_features)] +#![no_core] +#![no_std] +#![no_main] diff --git a/tests/run-make/branch-protection-check-IBT/rmake.rs b/tests/run-make/branch-protection-check-IBT/rmake.rs new file mode 100644 index 00000000000..73109df12ae --- /dev/null +++ b/tests/run-make/branch-protection-check-IBT/rmake.rs @@ -0,0 +1,53 @@ +// ignore-tidy-linelength +//! A basic smoke test to check for GNU Property Note to see that for `x86_64` targets when [`-Z +//! cf-protection=branch`][intel-cet-tracking-issue] is requested, that the +//! +//! ```text +//! NT_GNU_PROPERTY_TYPE_0 Properties: x86 feature: IBT +//! ``` +//! +//! Intel Indirect Branch Tracking (IBT) property is emitted. This was generated in +//! <https://github.com/rust-lang/rust/pull/110304> in order to address +//! <https://github.com/rust-lang/rust/issues/103001>. +//! +//! Note that the precompiled std currently is not compiled with `-Z cf-protection=branch`! +//! +//! In particular, it is expected that: +//! +//! > IBT to only be enabled for the process if `.note.gnu.property` indicates that the executable +//! > was compiled with IBT support and the linker to only tell that IBT is supported if all input +//! > object files indicate that they support IBT, which in turn requires the standard library to be +//! > compiled with IBT enabled. +//! +//! Note that Intel IBT (Indirect Branch Tracking) is not to be confused with Arm's BTI (Branch +//! Target Identification). See below for link to Intel IBT docs. +//! +//! ## Related links +//! +//! - [Tracking Issue for Intel Control Enforcement Technology (CET)][intel-cet-tracking-issue] +//! - Zulip question about this test: +//! <https://rust-lang.zulipchat.com/#narrow/channel/182449-t-compiler.2Fhelp/topic/.E2.9C.94.20Branch.20protection.20and.20.60.2Enote.2Egnu.2Eproperty.60> +//! - Intel IBT docs: +//! <https://edc.intel.com/content/www/us/en/design/ipla/software-development-platforms/client/platforms/alder-lake-desktop/12th-generation-intel-core-processors-datasheet-volume-1-of-2/006/indirect-branch-tracking/> +//! +//! [intel-cet-tracking-issue]: https://github.com/rust-lang/rust/issues/93754 + +//@ needs-llvm-components: x86 + +// FIXME(#93754): increase the test coverage of this test. +//@ only-x86_64-unknown-linux-gnu +//@ ignore-cross-compile + +use run_make_support::{bare_rustc, llvm_readobj}; + +fn main() { + // `main.rs` is `#![no_std]` to not pull in the currently not-compiled-with-IBT precompiled std. + bare_rustc() + .input("main.rs") + .target("x86_64-unknown-linux-gnu") + .arg("-Zcf-protection=branch") + .arg("-Clink-args=-nostartfiles") + .run(); + + llvm_readobj().arg("-nW").input("main").run().assert_stdout_contains(".note.gnu.property"); +} diff --git a/tests/run-make/libs-through-symlinks/Makefile b/tests/run-make/libs-through-symlinks/Makefile deleted file mode 100644 index c6ff566a0e8..00000000000 --- a/tests/run-make/libs-through-symlinks/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# ignore-windows - -# The option -n for the AIX ln command has a different purpose than it does -# on Linux. On Linux, the -n option is used to treat the destination path as -# normal file if it is a symbolic link to a directory, which is the default -# behavior of the AIX ln command. -ifeq ($(UNAME),AIX) -LN_FLAGS := -sf -else -LN_FLAGS := -nsf -endif - -NAME := $(shell $(RUSTC) --print file-names foo.rs) - -all: - mkdir -p $(TMPDIR)/outdir - $(RUSTC) foo.rs -o $(TMPDIR)/outdir/$(NAME) - ln $(LN_FLAGS) outdir/$(NAME) $(TMPDIR) - RUSTC_LOG=rustc_metadata::loader $(RUSTC) bar.rs diff --git a/tests/run-make/libs-through-symlinks/rmake.rs b/tests/run-make/libs-through-symlinks/rmake.rs new file mode 100644 index 00000000000..4bb3d05abb7 --- /dev/null +++ b/tests/run-make/libs-through-symlinks/rmake.rs @@ -0,0 +1,48 @@ +//! Regression test for [rustc doesn't handle relative symlinks to libraries +//! #13890](https://github.com/rust-lang/rust/issues/13890). +//! +//! This smoke test checks that for a given library search path `P`: +//! +//! - `rustc` is able to locate a library available via a symlink, where: +//! - the symlink is under the directory subtree of `P`, +//! - but the actual library is not (it's in a different directory subtree). +//! +//! For example: +//! +//! ```text +//! actual_dir/ +//! libfoo.rlib +//! symlink_dir/ # $CWD set; rustc -L . bar.rs that depends on foo +//! libfoo.rlib --> ../actual_dir/libfoo.rlib +//! ``` +//! +//! Previously, if `rustc` was invoked with CWD set to `symlink_dir/`, it would fail to traverse the +//! symlink to locate `actual_dir/libfoo.rlib`. This was originally fixed in +//! <https://github.com/rust-lang/rust/pull/13903>. + +//@ ignore-cross-compile + +use run_make_support::{bare_rustc, cwd, path, rfs, rust_lib_name}; + +fn main() { + let actual_lib_dir = path("actual_lib_dir"); + let symlink_lib_dir = path("symlink_lib_dir"); + rfs::create_dir_all(&actual_lib_dir); + rfs::create_dir_all(&symlink_lib_dir); + + // NOTE: `bare_rustc` is used because it does not introduce an implicit `-L .` library search + // flag. + bare_rustc().input("foo.rs").output(actual_lib_dir.join(rust_lib_name("foo"))).run(); + + rfs::symlink_file( + actual_lib_dir.join(rust_lib_name("foo")), + symlink_lib_dir.join(rust_lib_name("foo")), + ); + + // Make rustc's $CWD be in the directory containing the symlink-to-lib. + bare_rustc() + .current_dir(&symlink_lib_dir) + .library_search_path(".") + .input(cwd().join("bar.rs")) + .run(); +} diff --git a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs index 94c7964392d..2b41020d307 100644 --- a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs +++ b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs @@ -77,6 +77,9 @@ static EXPRS: &[&str] = &[ // These mean different things. "if let _ = true && false {}", "if let _ = (true && false) {}", + // Parentheses to call a named field, but not an unnamed field. + "(self.fun)()", + "self.0()", // Conditions end at the first curly brace, so struct expressions need to be // parenthesized. Except in a match guard, where conditions end at arrow. "if let _ = (Struct {}) {}", @@ -108,6 +111,10 @@ static EXPRS: &[&str] = &[ "{ (match 2 {})() - 1 }", "{ (match 2 {})[0] - 1 }", "{ (loop {}) - 1 }", + "match 2 { _ => (loop {}) - 1 }", + // No eager statement boundary if followed by `.` or `?`. + "{ loop {}.to_string() - 1 }", + "match 2 { _ => loop {}.to_string() - 1 }", // Angle bracket is eagerly parsed as a path's generic argument list. "(2 as T) < U", "(2 as T<U>) < V", // FIXME: no parentheses needed. diff --git a/tests/ui/consts/error-is-freeze.rs b/tests/ui/consts/error-is-freeze.rs new file mode 100644 index 00000000000..fe27d029e66 --- /dev/null +++ b/tests/ui/consts/error-is-freeze.rs @@ -0,0 +1,14 @@ +// Make sure we treat the error type as freeze to suppress useless errors. + +struct MyStruct { + foo: Option<UndefinedType>, + //~^ ERROR cannot find type `UndefinedType` in this scope +} +impl MyStruct { + pub const EMPTY_REF: &'static Self = &Self::EMPTY; + pub const EMPTY: Self = Self { + foo: None, + }; +} + +fn main() {} diff --git a/tests/ui/consts/error-is-freeze.stderr b/tests/ui/consts/error-is-freeze.stderr new file mode 100644 index 00000000000..f3bfd1ea5e2 --- /dev/null +++ b/tests/ui/consts/error-is-freeze.stderr @@ -0,0 +1,14 @@ +error[E0412]: cannot find type `UndefinedType` in this scope + --> $DIR/error-is-freeze.rs:4:17 + | +LL | foo: Option<UndefinedType>, + | ^^^^^^^^^^^^^ not found in this scope + | +help: you might be missing a type parameter + | +LL | struct MyStruct<UndefinedType> { + | +++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/tests/crashes/131050.rs b/tests/ui/impl-trait/auto-trait-contains-err.rs index 3e3a600ef3d..d7f094211d7 100644 --- a/tests/crashes/131050.rs +++ b/tests/ui/impl-trait/auto-trait-contains-err.rs @@ -1,9 +1,9 @@ -//@ known-bug: #131050 //@ compile-flags: --edition=2021 use std::future::Future; fn invalid_future() -> impl Future {} +//~^ ERROR `()` is not a future fn create_complex_future() -> impl Future<Output = impl ReturnsSend> { async { &|| async { invalid_future().await } } @@ -21,3 +21,5 @@ where R: Send, { } + +fn main() {} diff --git a/tests/ui/impl-trait/auto-trait-contains-err.stderr b/tests/ui/impl-trait/auto-trait-contains-err.stderr new file mode 100644 index 00000000000..4da6b285ae1 --- /dev/null +++ b/tests/ui/impl-trait/auto-trait-contains-err.stderr @@ -0,0 +1,11 @@ +error[E0277]: `()` is not a future + --> $DIR/auto-trait-contains-err.rs:5:24 + | +LL | fn invalid_future() -> impl Future {} + | ^^^^^^^^^^^ `()` is not a future + | + = help: the trait `Future` is not implemented for `()` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/structs/manual-default-impl-could-be-derived.rs b/tests/ui/structs/manual-default-impl-could-be-derived.rs new file mode 100644 index 00000000000..773b7389988 --- /dev/null +++ b/tests/ui/structs/manual-default-impl-could-be-derived.rs @@ -0,0 +1,194 @@ +// Warn when we encounter a manual `Default` impl that could be derived. +// Restricted only to types using `default_field_values`. +#![feature(default_field_values)] +#![allow(dead_code)] +#![deny(default_overrides_default_fields)] +struct S(i32); +fn s() -> S { S(1) } + +struct A { + x: S, + y: i32 = 1, +} + +impl Default for A { //~ ERROR default_overrides_default_fields + fn default() -> Self { + A { + y: 0, + x: s(), + } + } +} + +struct B { + x: S = S(3), + y: i32 = 1, +} + +impl Default for B { //~ ERROR default_overrides_default_fields + fn default() -> Self { + B { + x: s(), + y: 0, + } + } +} + +struct C { + x: S, + y: i32 = 1, + z: i32 = 1, +} + +impl Default for C { //~ ERROR default_overrides_default_fields + fn default() -> Self { + C { + x: s(), + y: 0, + .. + } + } +} + +struct D { + x: S, + y: i32 = 1, + z: i32 = 1, +} + +impl Default for D { //~ ERROR default_overrides_default_fields + fn default() -> Self { + D { + y: 0, + x: s(), + .. + } + } +} + +struct E { + x: S, + y: i32 = 1, + z: i32 = 1, +} + +impl Default for E { //~ ERROR default_overrides_default_fields + fn default() -> Self { + E { + y: 0, + z: 0, + x: s(), + } + } +} + +// Let's ensure that the span for `x` and the span for `y` don't overlap when suggesting their +// removal in favor of their default field values. +struct E2 { + x: S, + y: i32 = 1, + z: i32 = 1, +} + +impl Default for E2 { //~ ERROR default_overrides_default_fields + fn default() -> Self { + E2 { + x: s(), + y: i(), + z: 0, + } + } +} + +fn i() -> i32 { + 1 +} + +// Account for a `const fn` being the `Default::default()` of a field's type. +struct F { + x: G, + y: i32 = 1, +} + +impl Default for F { //~ ERROR default_overrides_default_fields + fn default() -> Self { + F { + x: g_const(), + y: 0, + } + } +} + +struct G; + +impl Default for G { // ok + fn default() -> Self { + g_const() + } +} + +const fn g_const() -> G { + G +} + +// Account for a `const fn` being used in `Default::default()`, even if the type doesn't use it as +// its own `Default`. We suggest setting the default field value in that case. +struct H { + x: I, + y: i32 = 1, +} + +impl Default for H { //~ ERROR default_overrides_default_fields + fn default() -> Self { + H { + x: i_const(), + y: 0, + } + } +} + +struct I; + +const fn i_const() -> I { + I +} + +// Account for a `const` and struct literal being the `Default::default()` of a field's type. +struct M { + x: N, + y: i32 = 1, + z: A, +} + +impl Default for M { // ok, `y` is not specified + fn default() -> Self { + M { + x: N_CONST, + z: A { + x: S(0), + y: 0, + }, + .. + } + } +} + +struct N; + +const N_CONST: N = N; + +struct O { + x: Option<i32>, + y: i32 = 1, +} + +impl Default for O { //~ ERROR default_overrides_default_fields + fn default() -> Self { + O { + x: None, + y: 1, + } + } +} + +fn main() {} diff --git a/tests/ui/structs/manual-default-impl-could-be-derived.stderr b/tests/ui/structs/manual-default-impl-could-be-derived.stderr new file mode 100644 index 00000000000..e8f607fac7e --- /dev/null +++ b/tests/ui/structs/manual-default-impl-could-be-derived.stderr @@ -0,0 +1,144 @@ +error: `Default` impl doesn't use the declared default field values + --> $DIR/manual-default-impl-could-be-derived.rs:14:1 + | +LL | / impl Default for A { +LL | | fn default() -> Self { +LL | | A { +LL | | y: 0, + | | - this field has a default value +... | +LL | | } + | |_^ + | + = help: use the default values in the `impl` with `Struct { mandatory_field, .. }` to avoid them diverging over time +note: the lint level is defined here + --> $DIR/manual-default-impl-could-be-derived.rs:5:9 + | +LL | #![deny(default_overrides_default_fields)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `Default` impl doesn't use the declared default field values + --> $DIR/manual-default-impl-could-be-derived.rs:28:1 + | +LL | / impl Default for B { +LL | | fn default() -> Self { +LL | | B { +LL | | x: s(), + | | --- this field has a default value +LL | | y: 0, + | | - this field has a default value +... | +LL | | } + | |_^ + | + = help: to avoid divergence in behavior between `Struct { .. }` and `<Struct as Default>::default()`, derive the `Default` + +error: `Default` impl doesn't use the declared default field values + --> $DIR/manual-default-impl-could-be-derived.rs:43:1 + | +LL | / impl Default for C { +LL | | fn default() -> Self { +LL | | C { +LL | | x: s(), +LL | | y: 0, + | | - this field has a default value +... | +LL | | } + | |_^ + | + = help: use the default values in the `impl` with `Struct { mandatory_field, .. }` to avoid them diverging over time + +error: `Default` impl doesn't use the declared default field values + --> $DIR/manual-default-impl-could-be-derived.rs:59:1 + | +LL | / impl Default for D { +LL | | fn default() -> Self { +LL | | D { +LL | | y: 0, + | | - this field has a default value +... | +LL | | } + | |_^ + | + = help: use the default values in the `impl` with `Struct { mandatory_field, .. }` to avoid them diverging over time + +error: `Default` impl doesn't use the declared default field values + --> $DIR/manual-default-impl-could-be-derived.rs:75:1 + | +LL | / impl Default for E { +LL | | fn default() -> Self { +LL | | E { +LL | | y: 0, + | | - this field has a default value +LL | | z: 0, + | | - this field has a default value +... | +LL | | } + | |_^ + | + = help: use the default values in the `impl` with `Struct { mandatory_field, .. }` to avoid them diverging over time + +error: `Default` impl doesn't use the declared default field values + --> $DIR/manual-default-impl-could-be-derived.rs:93:1 + | +LL | / impl Default for E2 { +LL | | fn default() -> Self { +LL | | E2 { +LL | | x: s(), +LL | | y: i(), + | | --- this field has a default value +LL | | z: 0, + | | - this field has a default value +... | +LL | | } + | |_^ + | + = help: use the default values in the `impl` with `Struct { mandatory_field, .. }` to avoid them diverging over time + +error: `Default` impl doesn't use the declared default field values + --> $DIR/manual-default-impl-could-be-derived.rs:113:1 + | +LL | / impl Default for F { +LL | | fn default() -> Self { +LL | | F { +LL | | x: g_const(), +LL | | y: 0, + | | - this field has a default value +... | +LL | | } + | |_^ + | + = help: use the default values in the `impl` with `Struct { mandatory_field, .. }` to avoid them diverging over time + +error: `Default` impl doesn't use the declared default field values + --> $DIR/manual-default-impl-could-be-derived.rs:141:1 + | +LL | / impl Default for H { +LL | | fn default() -> Self { +LL | | H { +LL | | x: i_const(), +LL | | y: 0, + | | - this field has a default value +... | +LL | | } + | |_^ + | + = help: use the default values in the `impl` with `Struct { mandatory_field, .. }` to avoid them diverging over time + +error: `Default` impl doesn't use the declared default field values + --> $DIR/manual-default-impl-could-be-derived.rs:185:1 + | +LL | / impl Default for O { +LL | | fn default() -> Self { +LL | | O { +LL | | x: None, +LL | | y: 1, + | | - this field has a default value +... | +LL | | } + | |_^ + | + = help: use the default values in the `impl` with `Struct { mandatory_field, .. }` to avoid them diverging over time + +error: aborting due to 9 previous errors + |
