diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 01fed72d5a270..bdd436302f489 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2349,6 +2349,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.report_missing_fields( adt_ty, path_span, + expr.span, remaining_fields, variant, hir_fields, @@ -2386,6 +2387,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, adt_ty: Ty<'tcx>, span: Span, + full_span: Span, remaining_fields: UnordMap, variant: &'tcx ty::VariantDef, hir_fields: &'tcx [hir::ExprField<'tcx>], @@ -2425,6 +2427,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); err.span_label(span, format!("missing {remaining_fields_names}{truncated_fields_error}")); + if remaining_fields.items().all(|(_, (_, field))| field.value.is_some()) + && self.tcx.sess.is_nightly_build() + { + let msg = format!( + "all remaining fields have default values, {you_can} use those values with `..`", + you_can = if self.tcx.features().default_field_values() { + "you can" + } else { + "if you added `#![feature(default_field_values)]` to your crate you could" + }, + ); + if let Some(hir_field) = hir_fields.last() { + err.span_suggestion_verbose( + hir_field.span.shrink_to_hi(), + msg, + ", ..".to_string(), + Applicability::MachineApplicable, + ); + } else if hir_fields.is_empty() { + err.span_suggestion_verbose( + span.shrink_to_hi().with_hi(full_span.hi()), + msg, + " { .. }".to_string(), + Applicability::MachineApplicable, + ); + } + } + if let Some(hir_field) = hir_fields.last() { self.suggest_fru_from_range_and_emit(hir_field, variant, args, err); } else { diff --git a/library/core/src/prelude/common.rs b/library/core/src/prelude/common.rs index e38ef1e147c76..8b116cecb5295 100644 --- a/library/core/src/prelude/common.rs +++ b/library/core/src/prelude/common.rs @@ -12,6 +12,9 @@ pub use crate::marker::{Copy, Send, Sized, Sync, Unpin}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] pub use crate::ops::{Drop, Fn, FnMut, FnOnce}; +#[stable(feature = "async_closure", since = "1.85.0")] +#[doc(no_inline)] +pub use crate::ops::{AsyncFn, AsyncFnMut, AsyncFnOnce}; // Re-exported functions #[stable(feature = "core_prelude", since = "1.4.0")] diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 0c526eafdf36f..1d26bf37f4d28 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -2387,13 +2387,12 @@ mod async_keyword {} /// [`async`]: ../std/keyword.async.html mod await_keyword {} -// FIXME(dyn_compat_renaming): Update URL and link text. #[doc(keyword = "dyn")] // /// `dyn` is a prefix of a [trait object]'s type. /// /// The `dyn` keyword is used to highlight that calls to methods on the associated `Trait` -/// are [dynamically dispatched]. To use the trait this way, it must be 'dyn-compatible'[^1]. +/// are [dynamically dispatched]. To use the trait this way, it must be *dyn compatible*[^1]. /// /// Unlike generic parameters or `impl Trait`, the compiler does not know the concrete type that /// is being passed. That is, the type has been [erased]. @@ -2406,7 +2405,7 @@ mod await_keyword {} /// the function pointer and then that function pointer is called. /// /// See the Reference for more information on [trait objects][ref-trait-obj] -/// and [object safety][ref-obj-safety]. +/// and [dyn compatibility][ref-dyn-compat]. /// /// ## Trade-offs /// @@ -2419,9 +2418,9 @@ mod await_keyword {} /// [trait object]: ../book/ch17-02-trait-objects.html /// [dynamically dispatched]: https://en.wikipedia.org/wiki/Dynamic_dispatch /// [ref-trait-obj]: ../reference/types/trait-object.html -/// [ref-obj-safety]: ../reference/items/traits.html#object-safety +/// [ref-dyn-compat]: ../reference/items/traits.html#dyn-compatibility /// [erased]: https://en.wikipedia.org/wiki/Type_erasure -/// [^1]: Formerly known as 'object safe'. +/// [^1]: Formerly known as *object safe*. mod dyn_keyword {} #[doc(keyword = "union")] diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index b3659351b8c11..f8493c21ad444 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -328,9 +328,6 @@ impl File { mem::size_of::() as u32, ); if result == 0 { - if api::get_last_error().code != 0 { - panic!("FILE_ALLOCATION_INFO failed!!!"); - } let eof = c::FILE_END_OF_FILE_INFO { EndOfFile: 0 }; let result = c::SetFileInformationByHandle( handle.as_raw_handle(), diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index d1bc0519bc1eb..d2697ac27ab7a 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -123,6 +123,7 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then build_args+=("--build-arg" "SCRIPT_ARG=${DOCKER_SCRIPT}") fi + GHCR_BUILDKIT_IMAGE="ghcr.io/rust-lang/buildkit:buildx-stable-1" # On non-CI jobs, we try to download a pre-built image from the rust-lang-ci # ghcr.io registry. If it is not possible, we fall back to building the image # locally. @@ -140,7 +141,9 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then elif [[ "$PR_CI_JOB" == "1" ]]; then # Enable a new Docker driver so that --cache-from works with a registry backend - docker buildx create --use --driver docker-container + # Use a custom image to avoid DockerHub rate limits + docker buildx create --use --driver docker-container \ + --driver-opt image=${GHCR_BUILDKIT_IMAGE} # Build the image using registry caching backend retry docker \ @@ -156,7 +159,9 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then --password-stdin # Enable a new Docker driver so that --cache-from/to works with a registry backend - docker buildx create --use --driver docker-container + # Use a custom image to avoid DockerHub rate limits + docker buildx create --use --driver docker-container \ + --driver-opt image=${GHCR_BUILDKIT_IMAGE} # Build the image using registry caching backend retry docker \ diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index c5b33a45db790..5e95e3721dfd2 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -48,6 +48,8 @@ runners: <<: *base-job - &job-aarch64-linux + # Free some disk space to avoid running out of space during the build. + free_disk: true os: ubuntu-22.04-arm envs: diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs index 8894ea7fb209b..b70db7130f677 100644 --- a/src/tools/run-make-support/src/external_deps/rustc.rs +++ b/src/tools/run-make-support/src/external_deps/rustc.rs @@ -1,5 +1,6 @@ use std::ffi::{OsStr, OsString}; -use std::path::Path; +use std::path::{Path, PathBuf}; +use std::str::FromStr as _; use crate::command::Command; use crate::env::env_var; @@ -390,3 +391,10 @@ impl Rustc { self } } + +/// Query the sysroot path corresponding `rustc --print=sysroot`. +#[track_caller] +pub fn sysroot() -> PathBuf { + let path = rustc().print("sysroot").run().stdout_utf8(); + PathBuf::from_str(path.trim()).unwrap() +} diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 567f0a256d98b..2e534c0fc2758 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -1,4 +1,3 @@ run-make/jobserver-error/Makefile run-make/split-debuginfo/Makefile run-make/symbol-mangling-hashed/Makefile -run-make/translation/Makefile diff --git a/tests/run-make/translation/Makefile b/tests/run-make/translation/Makefile deleted file mode 100644 index 07e0547cfa090..0000000000000 --- a/tests/run-make/translation/Makefile +++ /dev/null @@ -1,78 +0,0 @@ -include ../tools.mk - -# This test uses `ln -s` rather than copying to save testing time, but its -# usage doesn't work on Windows. -# ignore-windows - -SYSROOT:=$(shell $(RUSTC) --print sysroot) -FAKEROOT=$(TMPDIR)/fakeroot -RUSTC_LOG:=rustc_error_messages -export RUSTC_TRANSLATION_NO_DEBUG_ASSERT:=1 - -all: normal custom missing broken sysroot sysroot-invalid sysroot-missing - -# Check that the test works normally, using the built-in fallback bundle. -normal: test.rs - $(RUSTC) $< 2>&1 | $(CGREP) "struct literal body without path" - -# Check that a primary bundle can be loaded and will be preferentially used -# where possible. -custom: test.rs working.ftl - $(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/working.ftl 2>&1 | $(CGREP) "this is a test message" - -# Check that a primary bundle with a broken message (e.g. a interpolated -# variable is missing) will use the fallback bundle. -missing: test.rs missing.ftl - $(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/missing.ftl 2>&1 | $(CGREP) "struct literal body without path" - -# Check that a primary bundle without the desired message will use the fallback -# bundle. -broken: test.rs broken.ftl - $(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/broken.ftl 2>&1 | $(CGREP) "struct literal body without path" - -# Check that a locale can be loaded from the sysroot given a language -# identifier by making a local copy of the sysroot and adding the custom locale -# to it. -sysroot: test.rs working.ftl - rm -rf $(FAKEROOT) - mkdir $(FAKEROOT) - ln -s $(SYSROOT)/* $(FAKEROOT) - rm -f $(FAKEROOT)/lib - mkdir $(FAKEROOT)/lib - ln -s $(SYSROOT)/lib/* $(FAKEROOT)/lib - rm -f $(FAKEROOT)/lib/rustlib - mkdir $(FAKEROOT)/lib/rustlib - ln -s $(SYSROOT)/lib/rustlib/* $(FAKEROOT)/lib/rustlib - rm -f $(FAKEROOT)/lib/rustlib/src - mkdir $(FAKEROOT)/lib/rustlib/src - ln -s $(SYSROOT)/lib/rustlib/src/* $(FAKEROOT)/lib/rustlib/src - # When download-rustc is enabled, `$(SYSROOT)` will have a share directory. Delete the link to it. - rm -f $(FAKEROOT)/share - mkdir -p $(FAKEROOT)/share/locale/zh-CN/ - ln -s $(CURDIR)/working.ftl $(FAKEROOT)/share/locale/zh-CN/basic-translation.ftl - $(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 | $(CGREP) "this is a test message" - -# Check that the compiler errors out when the sysroot requested cannot be -# found. This test might start failing if there actually exists a Klingon -# translation of rustc's error messages. -sysroot-missing: - $(RUSTC) $< -Ztranslate-lang=tlh 2>&1 | $(CGREP) "missing locale directory" - -# Check that the compiler errors out when the directory for the locale in the -# sysroot is actually a file. -sysroot-invalid: test.rs working.ftl - rm -rf $(FAKEROOT) - mkdir $(FAKEROOT) - ln -s $(SYSROOT)/* $(FAKEROOT) - rm -f $(FAKEROOT)/lib - mkdir $(FAKEROOT)/lib - ln -s $(SYSROOT)/lib/* $(FAKEROOT)/lib - rm -f $(FAKEROOT)/lib/rustlib - mkdir $(FAKEROOT)/lib/rustlib - ln -s $(SYSROOT)/lib/rustlib/* $(FAKEROOT)/lib/rustlib - rm -f $(FAKEROOT)/lib/rustlib/src - mkdir $(FAKEROOT)/lib/rustlib/src - ln -s $(SYSROOT)/lib/rustlib/src/* $(FAKEROOT)/lib/rustlib/src - mkdir -p $(FAKEROOT)/share/locale - touch $(FAKEROOT)/share/locale/zh-CN - $(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 | $(CGREP) "`\$sysroot/share/locales/\$locale` is not a directory" diff --git a/tests/run-make/translation/rmake.rs b/tests/run-make/translation/rmake.rs new file mode 100644 index 0000000000000..c23cb80e14fc7 --- /dev/null +++ b/tests/run-make/translation/rmake.rs @@ -0,0 +1,179 @@ +//! Smoke test for the rustc diagnostics translation infrastructure. +//! +//! # References +//! +//! - Current tracking issue: . +//! - Old tracking issue: +//! - Initial translation infra implementation: . + +// This test uses symbolic links to stub out a fake sysroot to save testing time. +//@ needs-symlink + +#![deny(warnings)] + +use std::path::{Path, PathBuf}; + +use run_make_support::rustc::sysroot; +use run_make_support::{cwd, rfs, run_in_tmpdir, rustc}; + +fn main() { + builtin_fallback_bundle(); + additional_primary_bundle(); + missing_slug_prefers_fallback_bundle(); + broken_primary_bundle_prefers_fallback_bundle(); + locale_sysroot(); + missing_sysroot(); + file_sysroot(); +} + +/// Check that the test works normally, using the built-in fallback bundle. +fn builtin_fallback_bundle() { + rustc().input("test.rs").run_fail().assert_stderr_contains("struct literal body without path"); +} + +/// Check that a primary bundle can be loaded and will be preferentially used where possible. +fn additional_primary_bundle() { + rustc() + .input("test.rs") + .arg("-Ztranslate-additional-ftl=working.ftl") + .run_fail() + .assert_stderr_contains("this is a test message"); +} + +/// Check that a primary bundle without the desired message will use the fallback bundle. +fn missing_slug_prefers_fallback_bundle() { + rustc() + .input("test.rs") + .arg("-Ztranslate-additional-ftl=missing.ftl") + .run_fail() + .assert_stderr_contains("struct literal body without path"); +} + +/// Check that a primary bundle with a broken message (e.g. an interpolated variable is not +/// provided) will use the fallback bundle. +fn broken_primary_bundle_prefers_fallback_bundle() { + // FIXME(#135817): as of the rmake.rs port, the compiler actually ICEs on the additional + // `broken.ftl`, even though the original intention seems to be that it should gracefully + // failover to the fallback bundle. + + rustc() + .env("RUSTC_ICE", "0") // disable ICE dump file, not needed + .input("test.rs") + .arg("-Ztranslate-additional-ftl=broken.ftl") + .run_fail() + .assert_exit_code(101); +} + +#[track_caller] +fn shallow_symlink_dir_entries(src_dir: &Path, dst_dir: &Path) { + for entry in rfs::read_dir(src_dir) { + let entry = entry.unwrap(); + let src_entry_path = entry.path(); + let src_filename = src_entry_path.file_name().unwrap(); + let meta = rfs::symlink_metadata(&src_entry_path); + + if meta.is_symlink() || meta.is_file() { + rfs::symlink_file(&src_entry_path, dst_dir.join(src_filename)); + } else if meta.is_dir() { + rfs::symlink_dir(&src_entry_path, dst_dir.join(src_filename)); + } else { + unreachable!() + } + } +} + +#[track_caller] +fn shallow_symlink_dir_entries_materialize_single_dir( + src_dir: &Path, + dst_dir: &Path, + dir_filename: &str, +) { + shallow_symlink_dir_entries(src_dir, dst_dir); + + // On Windows, this would be a symlink-to-dir, so we have to remove with `remove_dir` instead. + #[cfg(windows)] + rfs::remove_dir(dst_dir.join(dir_filename)); + #[cfg(not(windows))] + rfs::remove_file(dst_dir.join(dir_filename)); + + rfs::create_dir_all(dst_dir.join(dir_filename)); +} + +#[track_caller] +fn setup_fakeroot_parents() -> PathBuf { + let sysroot = sysroot(); + let fakeroot = cwd().join("fakeroot"); + rfs::create_dir_all(&fakeroot); + shallow_symlink_dir_entries_materialize_single_dir(&sysroot, &fakeroot, "lib"); + shallow_symlink_dir_entries_materialize_single_dir( + &sysroot.join("lib"), + &fakeroot.join("lib"), + "rustlib", + ); + shallow_symlink_dir_entries_materialize_single_dir( + &sysroot.join("lib").join("rustlib"), + &fakeroot.join("lib").join("rustlib"), + "src", + ); + shallow_symlink_dir_entries( + &sysroot.join("lib").join("rustlib").join("src"), + &fakeroot.join("lib").join("rustlib").join("src"), + ); + fakeroot +} + +/// Check that a locale can be loaded from the sysroot given a language identifier by making a local +/// copy of the sysroot and adding the custom locale to it. +fn locale_sysroot() { + run_in_tmpdir(|| { + let fakeroot = setup_fakeroot_parents(); + + // When download-rustc is enabled, real sysroot will have a share directory. Delete the link + // to it. + let _ = std::fs::remove_file(fakeroot.join("share")); + + let fake_locale_path = fakeroot.join("share").join("locale").join("zh-CN"); + rfs::create_dir_all(&fake_locale_path); + rfs::symlink_file( + cwd().join("working.ftl"), + fake_locale_path.join("basic-translation.ftl"), + ); + + rustc() + .env("RUSTC_ICE", "0") + .input("test.rs") + .sysroot(&fakeroot) + .arg("-Ztranslate-lang=zh-CN") + .run_fail() + .assert_stderr_contains("this is a test message"); + }); +} + +/// Check that the compiler errors out when the sysroot requested cannot be found. This test might +/// start failing if there actually exists a Klingon translation of rustc's error messages. +fn missing_sysroot() { + run_in_tmpdir(|| { + rustc() + .input("test.rs") + .arg("-Ztranslate-lang=tlh") + .run_fail() + .assert_stderr_contains("missing locale directory"); + }); +} + +/// Check that the compiler errors out when the directory for the locale in the sysroot is actually +/// a file. +fn file_sysroot() { + run_in_tmpdir(|| { + let fakeroot = setup_fakeroot_parents(); + rfs::create_dir_all(fakeroot.join("share").join("locale")); + rfs::write(fakeroot.join("share").join("locale").join("zh-CN"), b"not a dir"); + + rustc() + .input("test.rs") + .sysroot(&fakeroot) + .arg("-Ztranslate-lang=zh-CN") + .run_fail() + .assert_stderr_contains("is not a directory"); + }); +} diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs index 37d94830db2cf..2a27164f9cba2 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs @@ -1,4 +1,6 @@ -//@ compile-flags: --test +// -Zpanic_abort_tests makes this test work on panic=abort targets and +// it's a no-op on panic=unwind targets +//@ compile-flags: --test -Zpanic_abort_tests //@ run-pass #![feature(core_intrinsics, generic_assert)] diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs index 86cc7adb90de6..254d59076e531 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs @@ -1,4 +1,6 @@ -//@ compile-flags: --test +// -Zpanic_abort_tests makes this test work on panic=abort targets and +// it's a no-op on panic=unwind targets +//@ compile-flags: --test -Zpanic_abort_tests // ignore-tidy-linelength //@ run-pass diff --git a/tests/ui/structs/default-field-values/non-exhaustive-ctor.disabled.stderr b/tests/ui/structs/default-field-values/non-exhaustive-ctor.disabled.stderr new file mode 100644 index 0000000000000..6379342565705 --- /dev/null +++ b/tests/ui/structs/default-field-values/non-exhaustive-ctor.disabled.stderr @@ -0,0 +1,86 @@ +error[E0658]: default values on fields are experimental + --> $DIR/non-exhaustive-ctor.rs:9:22 + | +LL | pub field: () = (), + | ^^^^^ + | + = note: see issue #132162 for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: default values on fields are experimental + --> $DIR/non-exhaustive-ctor.rs:11:25 + | +LL | pub field1: Priv = Priv, + | ^^^^^^^ + | + = note: see issue #132162 for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: default values on fields are experimental + --> $DIR/non-exhaustive-ctor.rs:13:25 + | +LL | pub field2: Priv = Priv, + | ^^^^^^^ + | + = note: see issue #132162 for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0797]: base expression required after `..` + --> $DIR/non-exhaustive-ctor.rs:20:19 + | +LL | let _ = S { .. }; // ok + | ^ + | +help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields + | +LL + #![feature(default_field_values)] + | +help: add a base expression here + | +LL | let _ = S { ../* expr */ }; // ok + | ++++++++++ + +error[E0797]: base expression required after `..` + --> $DIR/non-exhaustive-ctor.rs:22:30 + | +LL | let _ = S { field: (), .. }; // ok + | ^ + | +help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields + | +LL + #![feature(default_field_values)] + | +help: add a base expression here + | +LL | let _ = S { field: (), ../* expr */ }; // ok + | ++++++++++ + +error[E0063]: missing fields `field`, `field1` and `field2` in initializer of `S` + --> $DIR/non-exhaustive-ctor.rs:24:13 + | +LL | let _ = S { }; + | ^ missing `field`, `field1` and `field2` + | +help: all remaining fields have default values, if you added `#![feature(default_field_values)]` to your crate you could use those values with `..` + | +LL | let _ = S { .. }; + | ~~~~~~ + +error[E0063]: missing fields `field1` and `field2` in initializer of `S` + --> $DIR/non-exhaustive-ctor.rs:26:13 + | +LL | let _ = S { field: () }; + | ^ missing `field1` and `field2` + | +help: all remaining fields have default values, if you added `#![feature(default_field_values)]` to your crate you could use those values with `..` + | +LL | let _ = S { field: (), .. }; + | ++++ + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0063, E0658, E0797. +For more information about an error, try `rustc --explain E0063`. diff --git a/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.fixed b/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.fixed new file mode 100644 index 0000000000000..7a371f993e809 --- /dev/null +++ b/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.fixed @@ -0,0 +1,28 @@ +//@ revisions: enabled disabled +//@[enabled] run-rustfix +#![allow(private_interfaces, dead_code)] +#![cfg_attr(enabled, feature(default_field_values))] +use m::S; + +mod m { + pub struct S { + pub field: () = (), + //[disabled]~^ ERROR default values on fields are experimental + pub field1: Priv = Priv, + //[disabled]~^ ERROR default values on fields are experimental + pub field2: Priv = Priv, + //[disabled]~^ ERROR default values on fields are experimental + } + struct Priv; +} + +fn main() { + let _ = S { .. }; // ok + //[disabled]~^ ERROR base expression required after `..` + let _ = S { field: (), .. }; // ok + //[disabled]~^ ERROR base expression required after `..` + let _ = S { .. }; + //~^ ERROR missing fields `field`, `field1` and `field2` + let _ = S { field: (), .. }; + //~^ ERROR missing fields `field1` and `field2` +} diff --git a/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.stderr b/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.stderr new file mode 100644 index 0000000000000..6d035ebdc4750 --- /dev/null +++ b/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.stderr @@ -0,0 +1,25 @@ +error[E0063]: missing fields `field`, `field1` and `field2` in initializer of `S` + --> $DIR/non-exhaustive-ctor.rs:24:13 + | +LL | let _ = S { }; + | ^ missing `field`, `field1` and `field2` + | +help: all remaining fields have default values, you can use those values with `..` + | +LL | let _ = S { .. }; + | ~~~~~~ + +error[E0063]: missing fields `field1` and `field2` in initializer of `S` + --> $DIR/non-exhaustive-ctor.rs:26:13 + | +LL | let _ = S { field: () }; + | ^ missing `field1` and `field2` + | +help: all remaining fields have default values, you can use those values with `..` + | +LL | let _ = S { field: (), .. }; + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0063`. diff --git a/tests/ui/structs/default-field-values/non-exhaustive-ctor.rs b/tests/ui/structs/default-field-values/non-exhaustive-ctor.rs new file mode 100644 index 0000000000000..b60b219f8bcf0 --- /dev/null +++ b/tests/ui/structs/default-field-values/non-exhaustive-ctor.rs @@ -0,0 +1,28 @@ +//@ revisions: enabled disabled +//@[enabled] run-rustfix +#![allow(private_interfaces, dead_code)] +#![cfg_attr(enabled, feature(default_field_values))] +use m::S; + +mod m { + pub struct S { + pub field: () = (), + //[disabled]~^ ERROR default values on fields are experimental + pub field1: Priv = Priv, + //[disabled]~^ ERROR default values on fields are experimental + pub field2: Priv = Priv, + //[disabled]~^ ERROR default values on fields are experimental + } + struct Priv; +} + +fn main() { + let _ = S { .. }; // ok + //[disabled]~^ ERROR base expression required after `..` + let _ = S { field: (), .. }; // ok + //[disabled]~^ ERROR base expression required after `..` + let _ = S { }; + //~^ ERROR missing fields `field`, `field1` and `field2` + let _ = S { field: () }; + //~^ ERROR missing fields `field1` and `field2` +}