From 61273b7e642979ee25b669fd7dea05051ed6520d Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Sun, 27 Mar 2022 15:41:13 -0700 Subject: [PATCH 01/14] Define a dedicated error type for `HandleOrNull` and `HandleOrInvalid`. Define a `NotHandle` type, that implements `std::error::Error`, and use it as the error type in `HandleOrNull` and `HandleOrInvalid`. --- library/std/src/error.rs | 4 ++++ library/std/src/os/windows/io/handle.rs | 26 +++++++++++++++++++------ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index c3cb71a5dee63..5e51dbf87549b 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -604,6 +604,10 @@ impl Error for alloc::collections::TryReserveError {} #[unstable(feature = "duration_checked_float", issue = "83400")] impl Error for time::FromFloatSecsError {} +#[cfg(windows)] +#[unstable(feature = "io_safety", issue = "87074")] +impl Error for crate::os::windows::io::NotHandle {} + // Copied from `any.rs`. impl dyn Error + 'static { /// Returns `true` if the inner type is the same as `T`. diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 120af9f99dd9b..4003f04731f7d 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -142,17 +142,17 @@ impl BorrowedHandle<'_> { } impl TryFrom for OwnedHandle { - type Error = (); + type Error = NotHandle; #[inline] - fn try_from(handle_or_null: HandleOrNull) -> Result { + fn try_from(handle_or_null: HandleOrNull) -> Result { let owned_handle = handle_or_null.0; if owned_handle.handle.is_null() { // Don't call `CloseHandle`; it'd be harmless, except that it could // overwrite the `GetLastError` error. forget(owned_handle); - Err(()) + Err(NotHandle(())) } else { Ok(owned_handle) } @@ -200,23 +200,37 @@ impl OwnedHandle { } impl TryFrom for OwnedHandle { - type Error = (); + type Error = NotHandle; #[inline] - fn try_from(handle_or_invalid: HandleOrInvalid) -> Result { + fn try_from(handle_or_invalid: HandleOrInvalid) -> Result { let owned_handle = handle_or_invalid.0; if owned_handle.handle == c::INVALID_HANDLE_VALUE { // Don't call `CloseHandle`; it'd be harmless, except that it could // overwrite the `GetLastError` error. forget(owned_handle); - Err(()) + Err(NotHandle(())) } else { Ok(owned_handle) } } } +/// This is the error type used by [`HandleOrInvalid`] and +/// [`HandleOrNull`] when attempting to convert into a handle, +/// to indicate that the value is not a handle. +#[unstable(feature = "io_safety", issue = "87074")] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct NotHandle(()); + +#[unstable(feature = "io_safety", issue = "87074")] +impl fmt::Display for NotHandle { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + "the return value of a Windows API call indicated an error".fmt(fmt) + } +} + impl AsRawHandle for BorrowedHandle<'_> { #[inline] fn as_raw_handle(&self) -> RawHandle { From c7e0ef5cabbdf42e54b69ec1760835ad2d611c02 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Sun, 27 Mar 2022 16:53:56 -0700 Subject: [PATCH 02/14] Fix an incorrect word in a comment. --- library/std/src/os/windows/io/handle.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 4003f04731f7d..f27ea785586fa 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -75,7 +75,7 @@ pub struct OwnedHandle { /// `NULL`. This ensures that such FFI calls cannot start using the handle without /// checking for `NULL` first. /// -/// This type concerns any value other than `NULL` to be valid, including `INVALID_HANDLE_VALUE`. +/// This type considers any value other than `NULL` to be valid, including `INVALID_HANDLE_VALUE`. /// This is because APIs that use `NULL` as their sentry value don't treat `INVALID_HANDLE_VALUE` /// as special. /// @@ -95,7 +95,7 @@ pub struct HandleOrNull(OwnedHandle); /// `INVALID_HANDLE_VALUE`. This ensures that such FFI calls cannot start using the handle without /// checking for `INVALID_HANDLE_VALUE` first. /// -/// This type concerns any value other than `INVALID_HANDLE_VALUE` to be valid, including `NULL`. +/// This type considers any value other than `INVALID_HANDLE_VALUE` to be valid, including `NULL`. /// This is because APIs that use `INVALID_HANDLE_VALUE` as their sentry value may return `NULL` /// under `windows_subsystem = "windows"` or other situations where I/O devices are detached. /// From fc3b8b34ea5f68180dc1d776df99357c00fe135b Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Sun, 27 Mar 2022 16:54:58 -0700 Subject: [PATCH 03/14] Move the `Error` impl for `NotHandle` out of platform-independent code. --- library/std/src/error.rs | 4 ---- library/std/src/os/windows/io/handle.rs | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 5e51dbf87549b..c3cb71a5dee63 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -604,10 +604,6 @@ impl Error for alloc::collections::TryReserveError {} #[unstable(feature = "duration_checked_float", issue = "83400")] impl Error for time::FromFloatSecsError {} -#[cfg(windows)] -#[unstable(feature = "io_safety", issue = "87074")] -impl Error for crate::os::windows::io::NotHandle {} - // Copied from `any.rs`. impl dyn Error + 'static { /// Returns `true` if the inner type is the same as `T`. diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index f27ea785586fa..32e454cee7edc 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -231,6 +231,9 @@ impl fmt::Display for NotHandle { } } +#[unstable(feature = "io_safety", issue = "87074")] +impl crate::error::Error for NotHandle {} + impl AsRawHandle for BorrowedHandle<'_> { #[inline] fn as_raw_handle(&self) -> RawHandle { From 0efbd34c7e0c5064e7df977189c9950b1074706b Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 28 Mar 2022 10:56:00 -0700 Subject: [PATCH 04/14] Split `NotHandle` into `NullHandleError` and `InvalidHandleError`. Also, make the display messages more specific, and remove the `Copy` implementation. --- library/std/src/os/windows/io/handle.rs | 45 +++++++++++++++++-------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 32e454cee7edc..707b8a301727c 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -142,17 +142,17 @@ impl BorrowedHandle<'_> { } impl TryFrom for OwnedHandle { - type Error = NotHandle; + type Error = NullHandleError; #[inline] - fn try_from(handle_or_null: HandleOrNull) -> Result { + fn try_from(handle_or_null: HandleOrNull) -> Result { let owned_handle = handle_or_null.0; if owned_handle.handle.is_null() { // Don't call `CloseHandle`; it'd be harmless, except that it could // overwrite the `GetLastError` error. forget(owned_handle); - Err(NotHandle(())) + Err(NullHandleError(())) } else { Ok(owned_handle) } @@ -200,39 +200,56 @@ impl OwnedHandle { } impl TryFrom for OwnedHandle { - type Error = NotHandle; + type Error = InvalidHandleError; #[inline] - fn try_from(handle_or_invalid: HandleOrInvalid) -> Result { + fn try_from(handle_or_invalid: HandleOrInvalid) -> Result { let owned_handle = handle_or_invalid.0; if owned_handle.handle == c::INVALID_HANDLE_VALUE { // Don't call `CloseHandle`; it'd be harmless, except that it could // overwrite the `GetLastError` error. forget(owned_handle); - Err(NotHandle(())) + Err(InvalidHandleError(())) } else { Ok(owned_handle) } } } -/// This is the error type used by [`HandleOrInvalid`] and -/// [`HandleOrNull`] when attempting to convert into a handle, -/// to indicate that the value is not a handle. +/// This is the error type used by [`HandleOrNull`] when attempting to convert +/// into a handle, to indicate that the value is null. #[unstable(feature = "io_safety", issue = "87074")] -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct NotHandle(()); +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct NullHandleError(()); #[unstable(feature = "io_safety", issue = "87074")] -impl fmt::Display for NotHandle { +impl fmt::Display for NullHandleError { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - "the return value of a Windows API call indicated an error".fmt(fmt) + "A HandleOrNull could not be converted to a handle because it was null".fmt(fmt) } } #[unstable(feature = "io_safety", issue = "87074")] -impl crate::error::Error for NotHandle {} +impl crate::error::Error for NullHandleError {} + +/// This is the error type used by [`HandleOrInvalid`] when attempting to +/// convert into a handle, to indicate that the value is +/// `INVALID_HANDLE_VALUE`. +#[unstable(feature = "io_safety", issue = "87074")] +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct InvalidHandleError(()); + +#[unstable(feature = "io_safety", issue = "87074")] +impl fmt::Display for InvalidHandleError { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + "A HandleOrInvalid could not be converted to a handle because it was INVALID_HANDLE_VALUE" + .fmt(fmt) + } +} + +#[unstable(feature = "io_safety", issue = "87074")] +impl crate::error::Error for InvalidHandleError {} impl AsRawHandle for BorrowedHandle<'_> { #[inline] From 6b75406f5a7b006f7c724c08c6a00d7696a3620d Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Mon, 28 Feb 2022 18:13:24 -0500 Subject: [PATCH 05/14] Create 2024 edition --- compiler/rustc_ast/src/token.rs | 2 +- .../src/standard_library_imports.rs | 1 + compiler/rustc_expand/src/mbe/macro_rules.rs | 2 +- compiler/rustc_session/src/session.rs | 5 ++++ compiler/rustc_span/src/edition.rs | 30 +++++++++++++++++-- compiler/rustc_span/src/lib.rs | 5 ++++ compiler/rustc_span/src/symbol.rs | 2 ++ library/core/src/prelude/mod.rs | 10 +++++++ library/std/src/lib.rs | 1 + library/std/src/prelude/mod.rs | 14 +++++++++ src/test/ui/hello.rs | 11 +++++-- src/test/ui/hello2021.rs | 6 ---- src/tools/rustfmt/src/bin/main.rs | 1 + src/tools/rustfmt/src/config/options.rs | 5 ++++ 14 files changed, 83 insertions(+), 12 deletions(-) delete mode 100644 src/test/ui/hello2021.rs diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 2132cdfc001b6..3e274107e7fb6 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -722,7 +722,7 @@ impl NonterminalKind { Edition::Edition2015 | Edition::Edition2018 => { NonterminalKind::PatParam { inferred: true } } - Edition::Edition2021 => NonterminalKind::PatWithOr, + Edition::Edition2021 | Edition::Edition2024 => NonterminalKind::PatWithOr, }, sym::pat_param => NonterminalKind::PatParam { inferred: false }, sym::expr => NonterminalKind::Expr, diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index 3571517d2b258..09ad5f9b3eaa9 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -70,6 +70,7 @@ pub fn inject( Edition2015 => sym::rust_2015, Edition2018 => sym::rust_2018, Edition2021 => sym::rust_2021, + Edition2024 => sym::rust_2024, }]) .map(|&symbol| Ident::new(symbol, span)) .collect(); diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 10b2b9f07e2a5..058b03530a39f 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -1033,7 +1033,7 @@ fn check_matcher_core( err.span_label(sp, format!("not allowed after `{}` fragments", kind)); if kind == NonterminalKind::PatWithOr - && sess.edition == Edition::Edition2021 + && sess.edition.rust_2021() && next_token.is_token(&BinOp(token::BinOpToken::Or)) { let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl( diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index eed0f1e09fffe..8ba859bed4d08 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -945,6 +945,11 @@ impl Session { self.opts.edition >= Edition::Edition2021 } + /// Are we allowed to use features from the Rust 2024 edition? + pub fn rust_2024(&self) -> bool { + self.opts.edition >= Edition::Edition2024 + } + pub fn edition(&self) -> Edition { self.opts.edition } diff --git a/compiler/rustc_span/src/edition.rs b/compiler/rustc_span/src/edition.rs index 511c2e8662697..065d3660e5008 100644 --- a/compiler/rustc_span/src/edition.rs +++ b/compiler/rustc_span/src/edition.rs @@ -22,13 +22,15 @@ pub enum Edition { Edition2018, /// The 2021 edition Edition2021, + /// The 2024 edition + Edition2024, } // Must be in order from oldest to newest. pub const ALL_EDITIONS: &[Edition] = - &[Edition::Edition2015, Edition::Edition2018, Edition::Edition2021]; + &[Edition::Edition2015, Edition::Edition2018, Edition::Edition2021, Edition::Edition2024]; -pub const EDITION_NAME_LIST: &str = "2015|2018|2021"; +pub const EDITION_NAME_LIST: &str = "2015|2018|2021|2024"; pub const DEFAULT_EDITION: Edition = Edition::Edition2015; @@ -40,6 +42,7 @@ impl fmt::Display for Edition { Edition::Edition2015 => "2015", Edition::Edition2018 => "2018", Edition::Edition2021 => "2021", + Edition::Edition2024 => "2024", }; write!(f, "{}", s) } @@ -51,6 +54,7 @@ impl Edition { Edition::Edition2015 => "rust_2015_compatibility", Edition::Edition2018 => "rust_2018_compatibility", Edition::Edition2021 => "rust_2021_compatibility", + Edition::Edition2024 => "rust_2024_compatibility", } } @@ -59,6 +63,7 @@ impl Edition { Edition::Edition2015 => sym::rust_2015_preview, Edition::Edition2018 => sym::rust_2018_preview, Edition::Edition2021 => sym::rust_2021_preview, + Edition::Edition2024 => sym::rust_2024_preview, } } @@ -67,8 +72,28 @@ impl Edition { Edition::Edition2015 => true, Edition::Edition2018 => true, Edition::Edition2021 => true, + Edition::Edition2024 => false, } } + + pub fn rust_2015(&self) -> bool { + *self == Edition::Edition2015 + } + + /// Are we allowed to use features from the Rust 2018 edition? + pub fn rust_2018(&self) -> bool { + *self >= Edition::Edition2018 + } + + /// Are we allowed to use features from the Rust 2021 edition? + pub fn rust_2021(&self) -> bool { + *self >= Edition::Edition2021 + } + + /// Are we allowed to use features from the Rust 2024 edition? + pub fn rust_2024(&self) -> bool { + *self >= Edition::Edition2024 + } } impl FromStr for Edition { @@ -78,6 +103,7 @@ impl FromStr for Edition { "2015" => Ok(Edition::Edition2015), "2018" => Ok(Edition::Edition2018), "2021" => Ok(Edition::Edition2021), + "2024" => Ok(Edition::Edition2024), _ => Err(()), } } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 6d7377927c291..9ae366a5fe811 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -698,6 +698,11 @@ impl Span { self.edition() >= edition::Edition::Edition2021 } + #[inline] + pub fn rust_2024(self) -> bool { + self.edition() >= edition::Edition::Edition2024 + } + /// Returns the source callee. /// /// Returns `None` if the supplied span has no expansion trace, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 2737c26708bc4..443f0a6db89ce 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1145,6 +1145,8 @@ symbols! { rust_2018_preview, rust_2021, rust_2021_preview, + rust_2024, + rust_2024_preview, rust_begin_unwind, rust_eh_catch_typeinfo, rust_eh_personality, diff --git a/library/core/src/prelude/mod.rs b/library/core/src/prelude/mod.rs index ccd36a428e296..3cd3a3b780e9c 100644 --- a/library/core/src/prelude/mod.rs +++ b/library/core/src/prelude/mod.rs @@ -45,3 +45,13 @@ pub mod rust_2021 { #[doc(no_inline)] pub use crate::convert::{TryFrom, TryInto}; } + +/// The 2024 edition of the core prelude. +/// +/// See the [module-level documentation](self) for more. +#[unstable(feature = "prelude_2024", issue = "none")] +pub mod rust_2024 { + #[unstable(feature = "prelude_2024", issue = "none")] + #[doc(no_inline)] + pub use super::rust_2021::*; +} diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 819ec10a4b4b6..a5cdc89c5b60e 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -279,6 +279,7 @@ #![feature(panic_info_message)] #![feature(panic_internals)] #![feature(portable_simd)] +#![feature(prelude_2024)] #![feature(ptr_as_uninit)] #![feature(raw_os_nonzero)] #![feature(slice_internals)] diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs index d4bf6aeefee57..c314bbbb68e57 100644 --- a/library/std/src/prelude/mod.rs +++ b/library/std/src/prelude/mod.rs @@ -132,3 +132,17 @@ pub mod rust_2021 { #[doc(no_inline)] pub use core::prelude::rust_2021::*; } + +/// The 2024 version of the prelude of The Rust Standard Library. +/// +/// See the [module-level documentation](self) for more. +#[unstable(feature = "prelude_2024", issue = "none")] +pub mod rust_2024 { + #[unstable(feature = "prelude_2024", issue = "none")] + #[doc(no_inline)] + pub use super::v1::*; + + #[unstable(feature = "prelude_2024", issue = "none")] + #[doc(no_inline)] + pub use core::prelude::rust_2024::*; +} diff --git a/src/test/ui/hello.rs b/src/test/ui/hello.rs index c207c25545eca..c66b7c60fb4ea 100644 --- a/src/test/ui/hello.rs +++ b/src/test/ui/hello.rs @@ -1,5 +1,12 @@ // run-pass +// revisions: e2015 e2018 e2021 e2024 -pub fn main() { - println!("hello, world"); +//[e2018] edition:2018 +//[e2021] edition:2021 +//[e2024] edition:2024 + +//[e2024] compile-flags: -Zunstable-options + +fn main() { + println!("hello"); } diff --git a/src/test/ui/hello2021.rs b/src/test/ui/hello2021.rs deleted file mode 100644 index 134d8af5bfb8a..0000000000000 --- a/src/test/ui/hello2021.rs +++ /dev/null @@ -1,6 +0,0 @@ -// run-pass -// edition:2021 - -fn main() { - println!("hello, 2021"); -} diff --git a/src/tools/rustfmt/src/bin/main.rs b/src/tools/rustfmt/src/bin/main.rs index ad10b9ede608f..8e871e61f2683 100644 --- a/src/tools/rustfmt/src/bin/main.rs +++ b/src/tools/rustfmt/src/bin/main.rs @@ -693,6 +693,7 @@ fn edition_from_edition_str(edition_str: &str) -> Result { "2015" => Ok(Edition::Edition2015), "2018" => Ok(Edition::Edition2018), "2021" => Ok(Edition::Edition2021), + "2024" => Ok(Edition::Edition2024), _ => Err(format_err!("Invalid value for `--edition`")), } } diff --git a/src/tools/rustfmt/src/config/options.rs b/src/tools/rustfmt/src/config/options.rs index d857c29be29c6..257a17b2703a9 100644 --- a/src/tools/rustfmt/src/config/options.rs +++ b/src/tools/rustfmt/src/config/options.rs @@ -423,6 +423,10 @@ pub enum Edition { #[doc_hint = "2021"] /// Edition 2021. Edition2021, + #[value = "2024"] + #[doc_hint = "2024"] + /// Edition 2024. + Edition2024, } impl Default for Edition { @@ -437,6 +441,7 @@ impl From for rustc_span::edition::Edition { Edition::Edition2015 => Self::Edition2015, Edition::Edition2018 => Self::Edition2018, Edition::Edition2021 => Self::Edition2021, + Edition::Edition2024 => Self::Edition2024, } } } From abf2b4c04d4d6a0a2c49562fde33ae1d46e6ead7 Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Mon, 28 Feb 2022 15:33:50 -0500 Subject: [PATCH 06/14] Stabilize `derive_default_enum` --- .../src/deriving/default.rs | 13 +---- compiler/rustc_feature/src/accepted.rs | 2 + compiler/rustc_feature/src/active.rs | 2 - compiler/rustc_feature/src/lib.rs | 2 +- compiler/rustc_infer/src/lib.rs | 2 +- compiler/rustc_middle/src/lib.rs | 2 +- compiler/rustc_session/src/lib.rs | 2 +- compiler/rustc_trait_selection/src/lib.rs | 2 +- library/core/src/lib.rs | 2 +- src/test/ui/deriving/deriving-default-enum.rs | 2 - src/test/ui/deriving/deriving-with-helper.rs | 1 - .../feature-gate-derive_default_enum.rs | 7 --- .../feature-gate-derive_default_enum.stderr | 13 ----- src/test/ui/macros/macros-nonfatal-errors.rs | 1 - .../ui/macros/macros-nonfatal-errors.stderr | 58 +++++++++---------- 15 files changed, 38 insertions(+), 73 deletions(-) delete mode 100644 src/test/ui/feature-gates/feature-gate-derive_default_enum.rs delete mode 100644 src/test/ui/feature-gates/feature-gate-derive_default_enum.stderr diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index ca83941f600ca..2c5260616c7da 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -46,18 +46,7 @@ pub fn expand_deriving_default( StaticStruct(_, fields) => { default_struct_substructure(cx, trait_span, substr, fields) } - StaticEnum(enum_def, _) => { - if !cx.sess.features_untracked().derive_default_enum { - rustc_session::parse::feature_err( - cx.parse_sess(), - sym::derive_default_enum, - span, - "deriving `Default` on enums is experimental", - ) - .emit(); - } - default_enum_substructure(cx, trait_span, enum_def) - } + StaticEnum(enum_def, _) => default_enum_substructure(cx, trait_span, enum_def), _ => cx.span_bug(trait_span, "method in `derive(Default)`"), } })), diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index e37251c9c2439..048039343a7a2 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -126,6 +126,8 @@ declare_features! ( (accepted, default_type_params, "1.0.0", None, None), /// Allows `#[deprecated]` attribute. (accepted, deprecated, "1.9.0", Some(29935), None), + /// Allows `#[derive(Default)]` and `#[default]` on enums. + (accepted, derive_default_enum, "1.62.0", Some(86985), None), /// Allows the use of destructuring assignments. (accepted, destructuring_assignment, "1.59.0", Some(71126), None), /// Allows `#[doc(alias = "...")]`. diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 28466315c8687..81863162df318 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -368,8 +368,6 @@ declare_features! ( (active, deprecated_safe, "1.61.0", Some(94978), None), /// Allows having using `suggestion` in the `#[deprecated]` attribute. (active, deprecated_suggestion, "1.61.0", Some(94785), None), - /// Allows `#[derive(Default)]` and `#[default]` on enums. - (active, derive_default_enum, "1.56.0", Some(86985), None), /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. (active, doc_auto_cfg, "1.58.0", Some(43781), None), /// Allows `#[doc(cfg(...))]`. diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index bfc537cfae2cb..940c4ecdcc23a 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -11,7 +11,7 @@ //! even if it is stabilized or removed, *do not remove it*. Instead, move the //! symbol to the `accepted` or `removed` modules respectively. -#![feature(derive_default_enum)] +#![cfg_attr(bootstrap, feature(derive_default_enum))] #![feature(once_cell)] mod accepted; diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 08e005364ce64..e859bcaec1206 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -17,7 +17,7 @@ #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(control_flow_enum)] -#![feature(derive_default_enum)] +#![cfg_attr(bootstrap, feature(derive_default_enum))] #![feature(extend_one)] #![feature(label_break_value)] #![feature(let_chains)] diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index fa2dad5ce25f0..cffcd6699b6e4 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -30,7 +30,7 @@ #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(core_intrinsics)] -#![feature(derive_default_enum)] +#![cfg_attr(bootstrap, feature(derive_default_enum))] #![feature(discriminant_kind)] #![feature(exhaustive_patterns)] #![feature(get_mut_unchecked)] diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 3151b025ffff7..054b18b6b633a 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -1,7 +1,7 @@ #![feature(crate_visibility_modifier)] -#![feature(derive_default_enum)] #![feature(if_let_guard)] #![feature(let_chains)] +#![cfg_attr(bootstrap, feature(derive_default_enum))] #![feature(let_else)] #![feature(min_specialization)] #![feature(never_type)] diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 7523b8441013a..2ae7f34a91e00 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -16,7 +16,7 @@ #![feature(box_patterns)] #![feature(control_flow_enum)] #![feature(crate_visibility_modifier)] -#![feature(derive_default_enum)] +#![cfg_attr(bootstrap, feature(derive_default_enum))] #![feature(drain_filter)] #![feature(hash_drain_filter)] #![feature(label_break_value)] diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 660f6d92fe184..dc6bec246b9fe 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -167,7 +167,7 @@ #![feature(const_precise_live_drops)] #![feature(const_refs_to_cell)] #![feature(decl_macro)] -#![feature(derive_default_enum)] +#![cfg_attr(bootstrap, feature(derive_default_enum))] #![feature(deprecated_suggestion)] #![feature(doc_cfg)] #![feature(doc_notable_trait)] diff --git a/src/test/ui/deriving/deriving-default-enum.rs b/src/test/ui/deriving/deriving-default-enum.rs index 931ff1a5847d4..d1a81c72c2fdc 100644 --- a/src/test/ui/deriving/deriving-default-enum.rs +++ b/src/test/ui/deriving/deriving-default-enum.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(derive_default_enum)] - // nb: does not impl Default #[derive(Debug, PartialEq)] struct NotDefault; diff --git a/src/test/ui/deriving/deriving-with-helper.rs b/src/test/ui/deriving/deriving-with-helper.rs index d8f0b27a2e5f6..1c30b0b6fba75 100644 --- a/src/test/ui/deriving/deriving-with-helper.rs +++ b/src/test/ui/deriving/deriving-with-helper.rs @@ -5,7 +5,6 @@ #![feature(lang_items)] #![feature(no_core)] #![feature(rustc_attrs)] -#![feature(derive_default_enum)] #![no_core] diff --git a/src/test/ui/feature-gates/feature-gate-derive_default_enum.rs b/src/test/ui/feature-gates/feature-gate-derive_default_enum.rs deleted file mode 100644 index 05a5d4e14223a..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-derive_default_enum.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[derive(Default)] //~ ERROR deriving `Default` on enums is experimental -enum Foo { - #[default] - Alpha, -} - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-derive_default_enum.stderr b/src/test/ui/feature-gates/feature-gate-derive_default_enum.stderr deleted file mode 100644 index 58dd4d508a709..0000000000000 --- a/src/test/ui/feature-gates/feature-gate-derive_default_enum.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: deriving `Default` on enums is experimental - --> $DIR/feature-gate-derive_default_enum.rs:1:10 - | -LL | #[derive(Default)] - | ^^^^^^^ - | - = note: see issue #86985 for more information - = help: add `#![feature(derive_default_enum)]` to the crate attributes to enable - = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/macros/macros-nonfatal-errors.rs b/src/test/ui/macros/macros-nonfatal-errors.rs index 98f64aa6f8025..e7a01f105de0b 100644 --- a/src/test/ui/macros/macros-nonfatal-errors.rs +++ b/src/test/ui/macros/macros-nonfatal-errors.rs @@ -5,7 +5,6 @@ #![feature(trace_macros, concat_idents)] #![feature(stmt_expr_attributes, arbitrary_enum_discriminant)] -#![feature(derive_default_enum)] use std::arch::asm; diff --git a/src/test/ui/macros/macros-nonfatal-errors.stderr b/src/test/ui/macros/macros-nonfatal-errors.stderr index 79e8db9c1d429..b3c6d07f96763 100644 --- a/src/test/ui/macros/macros-nonfatal-errors.stderr +++ b/src/test/ui/macros/macros-nonfatal-errors.stderr @@ -1,41 +1,41 @@ error: the `#[default]` attribute may only be used on unit enum variants - --> $DIR/macros-nonfatal-errors.rs:14:5 + --> $DIR/macros-nonfatal-errors.rs:13:5 | LL | #[default] | ^^^^^^^^^^ error: the `#[default]` attribute may only be used on unit enum variants - --> $DIR/macros-nonfatal-errors.rs:19:36 + --> $DIR/macros-nonfatal-errors.rs:18:36 | LL | struct DefaultInnerAttrTupleStruct(#[default] ()); | ^^^^^^^^^^ error: the `#[default]` attribute may only be used on unit enum variants - --> $DIR/macros-nonfatal-errors.rs:23:1 + --> $DIR/macros-nonfatal-errors.rs:22:1 | LL | #[default] | ^^^^^^^^^^ error: the `#[default]` attribute may only be used on unit enum variants - --> $DIR/macros-nonfatal-errors.rs:27:1 + --> $DIR/macros-nonfatal-errors.rs:26:1 | LL | #[default] | ^^^^^^^^^^ error: the `#[default]` attribute may only be used on unit enum variants - --> $DIR/macros-nonfatal-errors.rs:37:11 + --> $DIR/macros-nonfatal-errors.rs:36:11 | LL | Foo = #[default] 0, | ^^^^^^^^^^ error: the `#[default]` attribute may only be used on unit enum variants - --> $DIR/macros-nonfatal-errors.rs:38:14 + --> $DIR/macros-nonfatal-errors.rs:37:14 | LL | Bar([u8; #[default] 1]), | ^^^^^^^^^^ error: no default declared - --> $DIR/macros-nonfatal-errors.rs:43:10 + --> $DIR/macros-nonfatal-errors.rs:42:10 | LL | #[derive(Default)] | ^^^^^^^ @@ -44,7 +44,7 @@ LL | #[derive(Default)] = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) error: multiple declared defaults - --> $DIR/macros-nonfatal-errors.rs:49:10 + --> $DIR/macros-nonfatal-errors.rs:48:10 | LL | #[derive(Default)] | ^^^^^^^ @@ -62,7 +62,7 @@ LL | Baz, = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) error: `#[default]` attribute does not accept a value - --> $DIR/macros-nonfatal-errors.rs:61:5 + --> $DIR/macros-nonfatal-errors.rs:60:5 | LL | #[default = 1] | ^^^^^^^^^^^^^^ @@ -70,7 +70,7 @@ LL | #[default = 1] = help: try using `#[default]` error: multiple `#[default]` attributes - --> $DIR/macros-nonfatal-errors.rs:69:5 + --> $DIR/macros-nonfatal-errors.rs:68:5 | LL | #[default] | ---------- `#[default]` used here @@ -81,13 +81,13 @@ LL | Foo, | = note: only one `#[default]` attribute is needed help: try removing this - --> $DIR/macros-nonfatal-errors.rs:68:5 + --> $DIR/macros-nonfatal-errors.rs:67:5 | LL | #[default] | ^^^^^^^^^^ error: multiple `#[default]` attributes - --> $DIR/macros-nonfatal-errors.rs:79:5 + --> $DIR/macros-nonfatal-errors.rs:78:5 | LL | #[default] | ---------- `#[default]` used here @@ -99,7 +99,7 @@ LL | Foo, | = note: only one `#[default]` attribute is needed help: try removing these - --> $DIR/macros-nonfatal-errors.rs:76:5 + --> $DIR/macros-nonfatal-errors.rs:75:5 | LL | #[default] | ^^^^^^^^^^ @@ -109,7 +109,7 @@ LL | #[default] | ^^^^^^^^^^ error: the `#[default]` attribute may only be used on unit enum variants - --> $DIR/macros-nonfatal-errors.rs:86:5 + --> $DIR/macros-nonfatal-errors.rs:85:5 | LL | Foo {}, | ^^^ @@ -117,7 +117,7 @@ LL | Foo {}, = help: consider a manual implementation of `Default` error: default variant must be exhaustive - --> $DIR/macros-nonfatal-errors.rs:94:5 + --> $DIR/macros-nonfatal-errors.rs:93:5 | LL | #[non_exhaustive] | ----------------- declared `#[non_exhaustive]` here @@ -127,37 +127,37 @@ LL | Foo, = help: consider a manual implementation of `Default` error: asm template must be a string literal - --> $DIR/macros-nonfatal-errors.rs:99:10 + --> $DIR/macros-nonfatal-errors.rs:98:10 | LL | asm!(invalid); | ^^^^^^^ error: concat_idents! requires ident args - --> $DIR/macros-nonfatal-errors.rs:102:5 + --> $DIR/macros-nonfatal-errors.rs:101:5 | LL | concat_idents!("not", "idents"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:104:17 + --> $DIR/macros-nonfatal-errors.rs:103:17 | LL | option_env!(invalid); | ^^^^^^^ error: expected string literal - --> $DIR/macros-nonfatal-errors.rs:105:10 + --> $DIR/macros-nonfatal-errors.rs:104:10 | LL | env!(invalid); | ^^^^^^^ error: expected string literal - --> $DIR/macros-nonfatal-errors.rs:106:10 + --> $DIR/macros-nonfatal-errors.rs:105:10 | LL | env!(foo, abr, baz); | ^^^ error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined - --> $DIR/macros-nonfatal-errors.rs:107:5 + --> $DIR/macros-nonfatal-errors.rs:106:5 | LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info) error: format argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:109:13 + --> $DIR/macros-nonfatal-errors.rs:108:13 | LL | format!(invalid); | ^^^^^^^ @@ -176,19 +176,19 @@ LL | format!("{}", invalid); | +++++ error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:111:14 + --> $DIR/macros-nonfatal-errors.rs:110:14 | LL | include!(invalid); | ^^^^^^^ error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:113:18 + --> $DIR/macros-nonfatal-errors.rs:112:18 | LL | include_str!(invalid); | ^^^^^^^ error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2) - --> $DIR/macros-nonfatal-errors.rs:114:5 + --> $DIR/macros-nonfatal-errors.rs:113:5 | LL | include_str!("i'd be quite surprised if a file with this name existed"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -196,13 +196,13 @@ LL | include_str!("i'd be quite surprised if a file with this name existed") = note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info) error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:115:20 + --> $DIR/macros-nonfatal-errors.rs:114:20 | LL | include_bytes!(invalid); | ^^^^^^^ error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2) - --> $DIR/macros-nonfatal-errors.rs:116:5 + --> $DIR/macros-nonfatal-errors.rs:115:5 | LL | include_bytes!("i'd be quite surprised if a file with this name existed"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -210,13 +210,13 @@ LL | include_bytes!("i'd be quite surprised if a file with this name existed = note: this error originates in the macro `include_bytes` (in Nightly builds, run with -Z macro-backtrace for more info) error: trace_macros! accepts only `true` or `false` - --> $DIR/macros-nonfatal-errors.rs:118:5 + --> $DIR/macros-nonfatal-errors.rs:117:5 | LL | trace_macros!(invalid); | ^^^^^^^^^^^^^^^^^^^^^^ error: cannot find macro `llvm_asm` in this scope - --> $DIR/macros-nonfatal-errors.rs:100:5 + --> $DIR/macros-nonfatal-errors.rs:99:5 | LL | llvm_asm!(invalid); | ^^^^^^^^ From a3dd654ae9f9002d3ff47e45a9a9b6afcb484d2f Mon Sep 17 00:00:00 2001 From: Jacob Pratt Date: Tue, 8 Mar 2022 15:44:52 -0500 Subject: [PATCH 07/14] Add documentation --- library/core/src/default.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/library/core/src/default.rs b/library/core/src/default.rs index fb862f7df947b..1ce00828bf344 100644 --- a/library/core/src/default.rs +++ b/library/core/src/default.rs @@ -52,6 +52,23 @@ /// This trait can be used with `#[derive]` if all of the type's fields implement /// `Default`. When `derive`d, it will use the default value for each field's type. /// +/// ### `enum`s +/// +/// When using `#[derive(Default)]` on an `enum`, you need to choose which unit variant will be +/// default. You do this by placing the `#[default]` attribute on the variant. +/// +/// ``` +/// #[derive(Default)] +/// enum Kind { +/// #[default] +/// A, +/// B, +/// C, +/// } +/// ``` +/// +/// You cannot use the `#[default]` attribute on non-unit or non-exhaustive variants. +/// /// ## How can I implement `Default`? /// /// Provide an implementation for the `default()` method that returns the value of From edeb826d0a6c157f389f94b8525794b52362e174 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 10 Apr 2022 12:23:42 -0700 Subject: [PATCH 08/14] Inline shallow_resolve_ty into ShallowResolver --- compiler/rustc_infer/src/infer/mod.rs | 83 +++++++++++++-------------- 1 file changed, 39 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 2524bd78355a1..e1cad1a4f6cef 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -1659,49 +1659,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.tcx.const_eval_resolve(param_env_erased, unevaluated, span) } - /// If `typ` is a type variable of some kind, resolve it one level - /// (but do not resolve types found in the result). If `typ` is - /// not a type variable, just return it unmodified. - // FIXME(eddyb) inline into `ShallowResolver::visit_ty`. - fn shallow_resolve_ty(&self, typ: Ty<'tcx>) -> Ty<'tcx> { - match *typ.kind() { - ty::Infer(ty::TyVar(v)) => { - // Not entirely obvious: if `typ` is a type variable, - // it can be resolved to an int/float variable, which - // can then be recursively resolved, hence the - // recursion. Note though that we prevent type - // variables from unifying to other type variables - // directly (though they may be embedded - // structurally), and we prevent cycles in any case, - // so this recursion should always be of very limited - // depth. - // - // Note: if these two lines are combined into one we get - // dynamic borrow errors on `self.inner`. - let known = self.inner.borrow_mut().type_variables().probe(v).known(); - known.map_or(typ, |t| self.shallow_resolve_ty(t)) - } - - ty::Infer(ty::IntVar(v)) => self - .inner - .borrow_mut() - .int_unification_table() - .probe_value(v) - .map(|v| v.to_type(self.tcx)) - .unwrap_or(typ), - - ty::Infer(ty::FloatVar(v)) => self - .inner - .borrow_mut() - .float_unification_table() - .probe_value(v) - .map(|v| v.to_type(self.tcx)) - .unwrap_or(typ), - - _ => typ, - } - } - /// `ty_or_const_infer_var_changed` is equivalent to one of these two: /// * `shallow_resolve(ty) != ty` (where `ty.kind = ty::Infer(_)`) /// * `shallow_resolve(ct) != ct` (where `ct.kind = ty::ConstKind::Infer(_)`) @@ -1831,8 +1788,46 @@ impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> { self.infcx.tcx } + /// If `ty` is a type variable of some kind, resolve it one level + /// (but do not resolve types found in the result). If `typ` is + /// not a type variable, just return it unmodified. fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.infcx.shallow_resolve_ty(ty) + match *ty.kind() { + ty::Infer(ty::TyVar(v)) => { + // Not entirely obvious: if `typ` is a type variable, + // it can be resolved to an int/float variable, which + // can then be recursively resolved, hence the + // recursion. Note though that we prevent type + // variables from unifying to other type variables + // directly (though they may be embedded + // structurally), and we prevent cycles in any case, + // so this recursion should always be of very limited + // depth. + // + // Note: if these two lines are combined into one we get + // dynamic borrow errors on `self.inner`. + let known = self.infcx.inner.borrow_mut().type_variables().probe(v).known(); + known.map_or(ty, |t| self.fold_ty(t)) + } + + ty::Infer(ty::IntVar(v)) => self + .infcx + .inner + .borrow_mut() + .int_unification_table() + .probe_value(v) + .map_or(ty, |v| v.to_type(self.infcx.tcx)), + + ty::Infer(ty::FloatVar(v)) => self + .infcx + .inner + .borrow_mut() + .float_unification_table() + .probe_value(v) + .map_or(ty, |v| v.to_type(self.infcx.tcx)), + + _ => ty, + } } fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { From 4a0f8d517529cdaca6750966536052b5104b05be Mon Sep 17 00:00:00 2001 From: rainy-me Date: Thu, 14 Apr 2022 03:22:02 +0900 Subject: [PATCH 09/14] improve diagnostics for unterminated nested block comment --- compiler/rustc_parse/src/lexer/mod.rs | 63 ++++++++++++++++--- src/test/ui/unterminated-nested-comment.rs | 4 ++ .../ui/unterminated-nested-comment.stderr | 21 +++++++ 3 files changed, 78 insertions(+), 10 deletions(-) create mode 100644 src/test/ui/unterminated-nested-comment.rs create mode 100644 src/test/ui/unterminated-nested-comment.stderr diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 5ab412dc777de..96513958eb06b 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -182,16 +182,7 @@ impl<'a> StringReader<'a> { } rustc_lexer::TokenKind::BlockComment { doc_style, terminated } => { if !terminated { - let msg = match doc_style { - Some(_) => "unterminated block doc-comment", - None => "unterminated block comment", - }; - let last_bpos = self.pos; - self.sess.span_diagnostic.span_fatal_with_code( - self.mk_sp(start, last_bpos), - msg, - error_code!(E0758), - ); + self.report_unterminated_block_comment(start, doc_style); } // Skip non-doc comments @@ -553,6 +544,58 @@ impl<'a> StringReader<'a> { err.emit() } + fn report_unterminated_block_comment(&self, start: BytePos, doc_style: Option) { + let msg = match doc_style { + Some(_) => "unterminated block doc-comment", + None => "unterminated block comment", + }; + let last_bpos = self.pos; + let mut err = self.sess.span_diagnostic.struct_span_fatal_with_code( + self.mk_sp(start, last_bpos), + msg, + error_code!(E0758), + ); + let mut nested_block_comment_open_idxs = vec![]; + let mut last_nested_block_comment_idxs = None; + let mut content_chars = self.str_from(start).char_indices(); + + if let Some((_, mut last_char)) = content_chars.next() { + while let Some((idx, c)) = content_chars.next() { + match c { + '*' if last_char == '/' => { + nested_block_comment_open_idxs.push(idx); + } + '/' if last_char == '*' => { + last_nested_block_comment_idxs = + nested_block_comment_open_idxs.pop().map(|open_idx| (open_idx, idx)); + } + _ => {} + }; + last_char = c; + } + } + + if let Some((nested_open_idx, nested_close_idx)) = last_nested_block_comment_idxs { + err.span_label(self.mk_sp(start, start + BytePos(2)), msg) + .span_label( + self.mk_sp( + start + BytePos(nested_open_idx as u32 - 1), + start + BytePos(nested_open_idx as u32 + 1), + ), + "...as last nested comment starts here, maybe you want to close this instead?", + ) + .span_label( + self.mk_sp( + start + BytePos(nested_close_idx as u32 - 1), + start + BytePos(nested_close_idx as u32 + 1), + ), + "...and last nested comment terminates here", + ); + } + + err.emit(); + } + // RFC 3101 introduced the idea of (reserved) prefixes. As of Rust 2021, // using a (unknown) prefix is an error. In earlier editions, however, they // only result in a (allowed by default) lint, and are treated as regular diff --git a/src/test/ui/unterminated-nested-comment.rs b/src/test/ui/unterminated-nested-comment.rs new file mode 100644 index 0000000000000..db5f2f3ba1358 --- /dev/null +++ b/src/test/ui/unterminated-nested-comment.rs @@ -0,0 +1,4 @@ +/* //~ ERROR E0758 +/* */ +/* +*/ diff --git a/src/test/ui/unterminated-nested-comment.stderr b/src/test/ui/unterminated-nested-comment.stderr new file mode 100644 index 0000000000000..eda8f2dcd2469 --- /dev/null +++ b/src/test/ui/unterminated-nested-comment.stderr @@ -0,0 +1,21 @@ +error[E0758]: unterminated block comment + --> $DIR/unterminated-nested-comment.rs:1:1 + | +LL | /* + | ^- + | | + | _unterminated block comment + | | +LL | | /* */ +LL | | /* + | | -- + | | | + | | ...as last nested comment starts here, maybe you want to close this instead? +LL | | */ + | |_--^ + | | + | ...and last nested comment terminates here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0758`. From 733ef089d9f59234e93f84dbe94472f0f9f2a34b Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Wed, 13 Apr 2022 14:32:17 -0700 Subject: [PATCH 10/14] Add a comment explaining the `(())` idiom for empty structs. --- library/std/src/os/windows/io/handle.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 707b8a301727c..1408b2e83f87a 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -219,6 +219,7 @@ impl TryFrom for OwnedHandle { /// This is the error type used by [`HandleOrNull`] when attempting to convert /// into a handle, to indicate that the value is null. +// The empty field prevents constructing this, and allows extending it in the future. #[unstable(feature = "io_safety", issue = "87074")] #[derive(Debug, Clone, PartialEq, Eq)] pub struct NullHandleError(()); @@ -236,6 +237,7 @@ impl crate::error::Error for NullHandleError {} /// This is the error type used by [`HandleOrInvalid`] when attempting to /// convert into a handle, to indicate that the value is /// `INVALID_HANDLE_VALUE`. +// The empty field prevents constructing this, and allows extending it in the future. #[unstable(feature = "io_safety", issue = "87074")] #[derive(Debug, Clone, PartialEq, Eq)] pub struct InvalidHandleError(()); From 849ede1cee9cca22683f9061f466cee82b738a36 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 13 Apr 2022 18:28:57 -0700 Subject: [PATCH 11/14] Update books --- src/doc/book | 2 +- src/doc/nomicon | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- src/doc/rustc-dev-guide | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/book b/src/doc/book index ea90bbaf53ba6..765318b844569 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit ea90bbaf53ba64ef4e2da9ac2352b298aec6bec8 +Subproject commit 765318b844569a642ceef7bf1adab9639cbf6af3 diff --git a/src/doc/nomicon b/src/doc/nomicon index 11f1165e8a2f5..c7d8467ca9158 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 11f1165e8a2f5840467e748c8108dc53c948ee9a +Subproject commit c7d8467ca9158da58ef295ae65dbf00a308752d9 diff --git a/src/doc/reference b/src/doc/reference index c97d14fa6fed0..b5f6c2362baf9 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit c97d14fa6fed0baa9255432b8a93cb70614f80e3 +Subproject commit b5f6c2362baf932db9440fbfcb509b309237ee85 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index ec954f35eedf5..c2a98d9fc5d29 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit ec954f35eedf592cd173b21c05a7f80a65b61d8a +Subproject commit c2a98d9fc5d29c481d42052fbeccfde15ed03116 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index 155126b1d2e2c..eeb5a83c15b6a 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit 155126b1d2e2cb01ddb1d7ba9489b90d7cd173ad +Subproject commit eeb5a83c15b6ae60df3e4f19207376b22c6fbc4c From f6d957701f8113d8c05e6a2397b93ad6fc450400 Mon Sep 17 00:00:00 2001 From: Boyd Kane <33420535+beyarkay@users.noreply.github.com> Date: Thu, 14 Apr 2022 09:51:47 +0200 Subject: [PATCH 12/14] docs: add link from zip to unzip The docs for `Iterator::unzip` explain that it is kind of an inverse operation to `Iterator::zip` and guide the reader to the `zip` docs, but the `zip` docs don't let the user know that they can undo the `zip` operation with `unzip`. This change modifies the docs to help the user find `unzip`. --- library/core/src/iter/traits/iterator.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 53fbe4cbc42f5..eae29278f5572 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -469,6 +469,10 @@ pub trait Iterator { /// If the zipped iterator has no more elements to return then each further attempt to advance /// it will first try to advance the first iterator at most one time and if it still yielded an item /// try to advance the second iterator at most one time. + /// + /// To 'undo' the result of zipping up two iterators, see [`unzip`]. + /// + /// [`unzip`]: Iterator::unzip /// /// # Examples /// From d73e32867f45690720c17422b83c8abc8ceff645 Mon Sep 17 00:00:00 2001 From: Boyd Kane <33420535+beyarkay@users.noreply.github.com> Date: Thu, 14 Apr 2022 11:19:49 +0200 Subject: [PATCH 13/14] Remove trailing whitespace Co-authored-by: Mara Bos --- library/core/src/iter/traits/iterator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index eae29278f5572..69f06fb06ef5d 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -469,7 +469,7 @@ pub trait Iterator { /// If the zipped iterator has no more elements to return then each further attempt to advance /// it will first try to advance the first iterator at most one time and if it still yielded an item /// try to advance the second iterator at most one time. - /// + /// /// To 'undo' the result of zipping up two iterators, see [`unzip`]. /// /// [`unzip`]: Iterator::unzip From 1b7008dc77e25049b04e5c3e31aecf4de00803e7 Mon Sep 17 00:00:00 2001 From: rainy-me Date: Thu, 14 Apr 2022 21:18:27 +0900 Subject: [PATCH 14/14] refactor: change to use peekable --- compiler/rustc_parse/src/lexer/mod.rs | 37 +++++++++---------- .../ui/unterminated-nested-comment.stderr | 2 +- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 96513958eb06b..e5ee1d5dab92e 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -557,39 +557,36 @@ impl<'a> StringReader<'a> { ); let mut nested_block_comment_open_idxs = vec![]; let mut last_nested_block_comment_idxs = None; - let mut content_chars = self.str_from(start).char_indices(); + let mut content_chars = self.str_from(start).char_indices().peekable(); - if let Some((_, mut last_char)) = content_chars.next() { - while let Some((idx, c)) = content_chars.next() { - match c { - '*' if last_char == '/' => { - nested_block_comment_open_idxs.push(idx); - } - '/' if last_char == '*' => { - last_nested_block_comment_idxs = - nested_block_comment_open_idxs.pop().map(|open_idx| (open_idx, idx)); - } - _ => {} - }; - last_char = c; - } + while let Some((idx, current_char)) = content_chars.next() { + match content_chars.peek() { + Some((_, '*')) if current_char == '/' => { + nested_block_comment_open_idxs.push(idx); + } + Some((_, '/')) if current_char == '*' => { + last_nested_block_comment_idxs = + nested_block_comment_open_idxs.pop().map(|open_idx| (open_idx, idx)); + } + _ => {} + }; } if let Some((nested_open_idx, nested_close_idx)) = last_nested_block_comment_idxs { err.span_label(self.mk_sp(start, start + BytePos(2)), msg) .span_label( self.mk_sp( - start + BytePos(nested_open_idx as u32 - 1), - start + BytePos(nested_open_idx as u32 + 1), + start + BytePos(nested_open_idx as u32), + start + BytePos(nested_open_idx as u32 + 2), ), "...as last nested comment starts here, maybe you want to close this instead?", ) .span_label( self.mk_sp( - start + BytePos(nested_close_idx as u32 - 1), - start + BytePos(nested_close_idx as u32 + 1), + start + BytePos(nested_close_idx as u32), + start + BytePos(nested_close_idx as u32 + 2), ), - "...and last nested comment terminates here", + "...and last nested comment terminates here.", ); } diff --git a/src/test/ui/unterminated-nested-comment.stderr b/src/test/ui/unterminated-nested-comment.stderr index eda8f2dcd2469..3653e76c9cbda 100644 --- a/src/test/ui/unterminated-nested-comment.stderr +++ b/src/test/ui/unterminated-nested-comment.stderr @@ -14,7 +14,7 @@ LL | | /* LL | | */ | |_--^ | | - | ...and last nested comment terminates here + | ...and last nested comment terminates here. error: aborting due to previous error