From ee1c2d583a081e24684e09fbbcc78fe4d5220066 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 May 2025 11:57:50 +1000 Subject: [PATCH 01/17] Remove `MetaItemListParser::all_{word,path}_list`, which are unused. --- compiler/rustc_attr_parsing/src/parser.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 077d953cfa318..a5c3cec3bdd40 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -561,20 +561,6 @@ impl<'a> MetaItemListParser<'a> { self.len() == 0 } - /// Asserts that every item in the list is another list starting with a word. - /// - /// See [`MetaItemParser::word`] for examples of words. - pub fn all_word_list<'s>(&'s self) -> Option)>> { - self.mixed().map(|i| i.meta_item()?.word()).collect() - } - - /// Asserts that every item in the list is another list starting with a full path. - /// - /// See [`MetaItemParser::path`] for examples of paths. - pub fn all_path_list<'s>(&'s self) -> Option, &'s ArgParser<'a>)>> { - self.mixed().map(|i| Some(i.meta_item()?.path())).collect() - } - /// Returns Some if the list contains only a single element. /// /// Inside the Some is the parser to parse this single element. From a822e557cd19efa0dcf62ae3e7af6b6310fa2f5c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 May 2025 12:01:03 +1000 Subject: [PATCH 02/17] Remove an unnecessary lifetime. --- compiler/rustc_attr_parsing/src/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index a5c3cec3bdd40..a9eb0a5188821 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -549,7 +549,7 @@ impl<'a> MetaItemListParser<'a> { } /// Lets you pick and choose as what you want to parse each element in the list - pub fn mixed<'s>(&'s self) -> impl Iterator> + 's { + pub fn mixed(&self) -> impl Iterator> { self.sub_parsers.iter() } From ea3b3fdcc155fb0cd758392b68b1859cf9a435b4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 May 2025 12:08:00 +1000 Subject: [PATCH 03/17] Remove `MetaItemParser::{word,word_without_args,path_is}`. They are unused. --- compiler/rustc_attr_parsing/src/parser.rs | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index a9eb0a5188821..8366f163a684d 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -276,38 +276,15 @@ impl<'a> MetaItemParser<'a> { self.deconstruct() } - /// Asserts that this MetaItem starts with a word, or single segment path. - /// Doesn't return the args parser. - /// - /// For examples. see [`Self::word`] - pub fn word_without_args(&self) -> Option { - Some(self.word()?.0) - } - /// Asserts that this MetaItem starts with a word, or single segment path. /// /// Some examples: /// - `#[inline]`: `inline` is a word /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path, /// and not a word and should instead be parsed using [`path`](Self::path) - pub fn word(&self) -> Option<(Ident, &ArgParser<'a>)> { - let (path, args) = self.deconstruct(); - Some((path.word()?, args)) - } - - /// Asserts that this MetaItem starts with some specific word. - /// - /// See [`word`](Self::word) for examples of what a word is. pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser<'a>> { self.path_without_args().word_is(sym).then(|| self.args()) } - - /// Asserts that this MetaItem starts with some specific path. - /// - /// See [`word`](Self::path) for examples of what a word is. - pub fn path_is(&self, segments: &[Symbol]) -> Option<&ArgParser<'a>> { - self.path_without_args().segments_is(segments).then(|| self.args()) - } } #[derive(Clone)] From 2cd2d249673b316bb4a15c10c6a1113b2bee02db Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 May 2025 11:57:21 +1000 Subject: [PATCH 04/17] Remove `MetaItemParser::{path,deconstruct}`. They're equivalent, and `path` is unused, and `deconstruct` has only one call site outside of `path`. --- compiler/rustc_attr_parsing/src/context.rs | 3 ++- compiler/rustc_attr_parsing/src/parser.rs | 19 +++++-------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 55c3df003fe16..820c70edebf8d 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -260,7 +260,8 @@ impl<'sess> AttributeParser<'sess> { // } ast::AttrKind::Normal(n) => { let parser = MetaItemParser::from_attr(n, self.dcx()); - let (path, args) = parser.deconstruct(); + let path = parser.path_without_args(); + let args = parser.args(); let parts = path.segments().map(|i| i.name).collect::>(); if let Some(accepts) = ATTRIBUTE_MAPPING.0.get(parts.as_slice()) { diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 8366f163a684d..30d8aa0272095 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -253,7 +253,11 @@ impl<'a> MetaItemParser<'a> { } } - /// Gets just the path, without the args. + /// Gets just the path, without the args. Some examples: + /// + /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path + /// - `#[allow(clippy::complexity)]`: `clippy::complexity` is a path + /// - `#[inline]`: `inline` is a single segment path pub fn path_without_args(&self) -> PathParser<'a> { self.path.clone() } @@ -263,19 +267,6 @@ impl<'a> MetaItemParser<'a> { &self.args } - pub fn deconstruct(&self) -> (PathParser<'a>, &ArgParser<'a>) { - (self.path_without_args(), self.args()) - } - - /// Asserts that this MetaItem starts with a path. Some examples: - /// - /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path - /// - `#[allow(clippy::complexity)]`: `clippy::complexity` is a path - /// - `#[inline]`: `inline` is a single segment path - pub fn path(&self) -> (PathParser<'a>, &ArgParser<'a>) { - self.deconstruct() - } - /// Asserts that this MetaItem starts with a word, or single segment path. /// /// Some examples: From e5c78de85c01e576671f9ba0c880520baf0d938d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 20 May 2025 12:41:56 +1000 Subject: [PATCH 05/17] Rename `MetaItemParser::path_without_args` as `MetaItemParser::path`. And avoid the clone. --- .../src/attributes/allow_unstable.rs | 2 +- .../rustc_attr_parsing/src/attributes/deprecation.rs | 4 ++-- compiler/rustc_attr_parsing/src/attributes/repr.rs | 2 +- .../rustc_attr_parsing/src/attributes/stability.rs | 10 +++++----- compiler/rustc_attr_parsing/src/context.rs | 2 +- compiler/rustc_attr_parsing/src/parser.rs | 6 +++--- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index c1d95d07f4c65..8460a4a412279 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -53,7 +53,7 @@ fn parse_unstable<'a>( for param in list.mixed() { let param_span = param.span(); - if let Some(ident) = param.meta_item().and_then(|i| i.path_without_args().word()) { + if let Some(ident) = param.meta_item().and_then(|i| i.path().word()) { res.push(ident.name); } else { cx.emit_err(session_diagnostics::ExpectsFeatures { diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index fb3d5f57d4fac..5e94261f1c49a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -79,7 +79,7 @@ impl SingleAttributeParser for DeprecationParser { return None; }; - let ident_name = param.path_without_args().word_sym(); + let ident_name = param.path().word_sym(); match ident_name { Some(name @ sym::since) => { @@ -102,7 +102,7 @@ impl SingleAttributeParser for DeprecationParser { _ => { cx.emit_err(session_diagnostics::UnknownMetaItem { span: param_span, - item: param.path_without_args().to_string(), + item: param.path().to_string(), expected: if features.deprecated_suggestion() { &["since", "note", "suggestion"] } else { diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 43dfb85a7c411..97c865230f2d0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -96,7 +96,7 @@ fn parse_repr(cx: &AcceptContext<'_>, param: &MetaItemParser<'_>) -> Option insert_value_into_option_or_error(cx, ¶m, &mut feature)?, Some(sym::since) => insert_value_into_option_or_error(cx, ¶m, &mut since)?, _ => { cx.emit_err(session_diagnostics::UnknownMetaItem { span: param_span, - item: param.path_without_args().to_string(), + item: param.path().to_string(), expected: &["feature", "since"], }); return None; @@ -310,7 +310,7 @@ pub(crate) fn parse_unstability( return None; }; - match param.path_without_args().word_sym() { + match param.path().word_sym() { Some(sym::feature) => insert_value_into_option_or_error(cx, ¶m, &mut feature)?, Some(sym::reason) => insert_value_into_option_or_error(cx, ¶m, &mut reason)?, Some(sym::issue) => { @@ -349,7 +349,7 @@ pub(crate) fn parse_unstability( _ => { cx.emit_err(session_diagnostics::UnknownMetaItem { span: param.span(), - item: param.path_without_args().to_string(), + item: param.path().to_string(), expected: &["feature", "reason", "issue", "soft", "implied_by"], }); return None; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 820c70edebf8d..c101785491665 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -260,7 +260,7 @@ impl<'sess> AttributeParser<'sess> { // } ast::AttrKind::Normal(n) => { let parser = MetaItemParser::from_attr(n, self.dcx()); - let path = parser.path_without_args(); + let path = parser.path(); let args = parser.args(); let parts = path.segments().map(|i| i.name).collect::>(); diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 30d8aa0272095..7e89f6c6a2e9a 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -258,8 +258,8 @@ impl<'a> MetaItemParser<'a> { /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path /// - `#[allow(clippy::complexity)]`: `clippy::complexity` is a path /// - `#[inline]`: `inline` is a single segment path - pub fn path_without_args(&self) -> PathParser<'a> { - self.path.clone() + pub fn path(&self) -> &PathParser<'a> { + &self.path } /// Gets just the args parser, without caring about the path. @@ -274,7 +274,7 @@ impl<'a> MetaItemParser<'a> { /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path, /// and not a word and should instead be parsed using [`path`](Self::path) pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser<'a>> { - self.path_without_args().word_is(sym).then(|| self.args()) + self.path().word_is(sym).then(|| self.args()) } } From 6b5b97a4df3331e82ee7f57f2c33818b997f98d0 Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 26 May 2025 13:47:53 +0800 Subject: [PATCH 06/17] Fix incorrect eq_unspanned in TokenStream --- compiler/rustc_ast/src/tokenstream.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 636c26bcde04b..7f2ba28f81bd8 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -696,14 +696,8 @@ impl TokenStream { /// Compares two `TokenStream`s, checking equality without regarding span information. pub fn eq_unspanned(&self, other: &TokenStream) -> bool { - let mut iter1 = self.iter(); - let mut iter2 = other.iter(); - for (tt1, tt2) in iter::zip(&mut iter1, &mut iter2) { - if !tt1.eq_unspanned(tt2) { - return false; - } - } - iter1.next().is_none() && iter2.next().is_none() + self.len() == other.len() + && self.iter().zip(other.iter()).all(|(tt1, tt2)| tt1.eq_unspanned(tt2)) } /// Create a token stream containing a single token with alone spacing. The From d3347bb32b01e73db96d75579ec7ca16320d4317 Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 26 May 2025 14:11:02 +0800 Subject: [PATCH 07/17] remove eq_unspanned from TokenStream --- compiler/rustc_ast/src/tokenstream.rs | 10 +++------- compiler/rustc_parse/src/parser/tokenstream/tests.rs | 8 ++++++-- src/tools/clippy/clippy_utils/src/ast_utils/mod.rs | 4 +++- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 7f2ba28f81bd8..3c231be20dce5 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -57,7 +57,9 @@ impl TokenTree { match (self, other) { (TokenTree::Token(token, _), TokenTree::Token(token2, _)) => token.kind == token2.kind, (TokenTree::Delimited(.., delim, tts), TokenTree::Delimited(.., delim2, tts2)) => { - delim == delim2 && tts.eq_unspanned(tts2) + delim == delim2 + && tts.len() == tts2.len() + && tts.iter().zip(tts2.iter()).all(|(a, b)| a.eq_unspanned(b)) } _ => false, } @@ -694,12 +696,6 @@ impl TokenStream { TokenStreamIter::new(self) } - /// Compares two `TokenStream`s, checking equality without regarding span information. - pub fn eq_unspanned(&self, other: &TokenStream) -> bool { - self.len() == other.len() - && self.iter().zip(other.iter()).all(|(tt1, tt2)| tt1.eq_unspanned(tt2)) - } - /// Create a token stream containing a single token with alone spacing. The /// spacing used for the final token in a constructed stream doesn't matter /// because it's never used. In practice we arbitrarily use diff --git a/compiler/rustc_parse/src/parser/tokenstream/tests.rs b/compiler/rustc_parse/src/parser/tokenstream/tests.rs index aac75323ff3d2..19b2c98f5af82 100644 --- a/compiler/rustc_parse/src/parser/tokenstream/tests.rs +++ b/compiler/rustc_parse/src/parser/tokenstream/tests.rs @@ -14,6 +14,10 @@ fn sp(a: u32, b: u32) -> Span { Span::with_root_ctxt(BytePos(a), BytePos(b)) } +fn cmp_token_stream(a: &TokenStream, b: &TokenStream) -> bool { + a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| x.eq_unspanned(y)) +} + #[test] fn test_concat() { create_default_session_globals_then(|| { @@ -25,7 +29,7 @@ fn test_concat() { eq_res.push_stream(test_snd); assert_eq!(test_res.iter().count(), 5); assert_eq!(eq_res.iter().count(), 5); - assert_eq!(test_res.eq_unspanned(&eq_res), true); + assert_eq!(cmp_token_stream(&test_res, &eq_res), true); }) } @@ -104,7 +108,7 @@ fn test_dotdotdot() { stream.push_tree(TokenTree::token_joint(token::Dot, sp(0, 1))); stream.push_tree(TokenTree::token_joint(token::Dot, sp(1, 2))); stream.push_tree(TokenTree::token_alone(token::Dot, sp(2, 3))); - assert!(stream.eq_unspanned(&string_to_ts("..."))); + assert!(cmp_token_stream(&stream, &string_to_ts("..."))); assert_eq!(stream.iter().count(), 1); }) } diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index 8996b694ed8f7..01e916fb5353b 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -960,5 +960,7 @@ pub fn eq_attr_args(l: &AttrArgs, r: &AttrArgs) -> bool { } pub fn eq_delim_args(l: &DelimArgs, r: &DelimArgs) -> bool { - l.delim == r.delim && l.tokens.eq_unspanned(&r.tokens) + l.delim == r.delim + && l.tokens.len() == r.tokens.len() + && l.tokens.iter().zip(r.tokens.iter()).all(|(a, b)| a.eq_unspanned(b)) } From 80e44de2d37c7f9597707cbba1287fdd03cdcae5 Mon Sep 17 00:00:00 2001 From: usamoi Date: Mon, 2 Jun 2025 17:49:28 +0800 Subject: [PATCH 08/17] remove f16: From --- library/core/src/convert/num.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs index d5cb10a5d1c8b..50616732b7776 100644 --- a/library/core/src/convert/num.rs +++ b/library/core/src/convert/num.rs @@ -175,7 +175,6 @@ impl_from!(u8 => f16, #[stable(feature = "lossless_float_conv", since = "1.6.0") impl_from!(u8 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u8 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u8 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); -impl_from!(u16 => f16, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u16 => f32, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); impl_from!(u16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]); From a20cf473e7b888f9ef7995971f0c5613a81e68ff Mon Sep 17 00:00:00 2001 From: Sidney Cammeresi Date: Mon, 2 Jun 2025 09:43:48 -0700 Subject: [PATCH 09/17] Lightly tweak docs for BTree{Map,Set}::extract_if - Move explanations into comments to match style - Explain the second examples - Make variable names match the data structure --- library/alloc/src/collections/btree/map.rs | 4 ++-- library/alloc/src/collections/btree/set.rs | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 52b98291ff93f..17c16e4aafff7 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1416,18 +1416,18 @@ impl BTreeMap { /// /// # Examples /// - /// Splitting a map into even and odd keys, reusing the original map: - /// /// ``` /// #![feature(btree_extract_if)] /// use std::collections::BTreeMap; /// + /// // Splitting a map into even and odd keys, reusing the original map: /// let mut map: BTreeMap = (0..8).map(|x| (x, x)).collect(); /// let evens: BTreeMap<_, _> = map.extract_if(.., |k, _v| k % 2 == 0).collect(); /// let odds = map; /// assert_eq!(evens.keys().copied().collect::>(), [0, 2, 4, 6]); /// assert_eq!(odds.keys().copied().collect::>(), [1, 3, 5, 7]); /// + /// // Splitting a map into low and high halves, reusing the original map: /// let mut map: BTreeMap = (0..8).map(|x| (x, x)).collect(); /// let low: BTreeMap<_, _> = map.extract_if(0..4, |_k, _v| true).collect(); /// let high = map; diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 780bd8b0dd143..51418036f428e 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1201,21 +1201,21 @@ impl BTreeSet { /// [`retain`]: BTreeSet::retain /// # Examples /// - /// Splitting a set into even and odd values, reusing the original set: - /// /// ``` /// #![feature(btree_extract_if)] /// use std::collections::BTreeSet; /// + /// // Splitting a set into even and odd values, reusing the original set: /// let mut set: BTreeSet = (0..8).collect(); /// let evens: BTreeSet<_> = set.extract_if(.., |v| v % 2 == 0).collect(); /// let odds = set; /// assert_eq!(evens.into_iter().collect::>(), vec![0, 2, 4, 6]); /// assert_eq!(odds.into_iter().collect::>(), vec![1, 3, 5, 7]); /// - /// let mut map: BTreeSet = (0..8).collect(); - /// let low: BTreeSet<_> = map.extract_if(0..4, |_v| true).collect(); - /// let high = map; + /// // Splitting a set into low and high halves, reusing the original set: + /// let mut set: BTreeSet = (0..8).collect(); + /// let low: BTreeSet<_> = set.extract_if(0..4, |_v| true).collect(); + /// let high = set; /// assert_eq!(low.into_iter().collect::>(), [0, 1, 2, 3]); /// assert_eq!(high.into_iter().collect::>(), [4, 5, 6, 7]); /// ``` From e87f1386d962732f2ffe69e876add4393e06d5a1 Mon Sep 17 00:00:00 2001 From: Jeremy Smart Date: Mon, 2 Jun 2025 20:37:55 -0400 Subject: [PATCH 10/17] add tests --- library/coretests/tests/lib.rs | 1 + library/coretests/tests/num/int_macros.rs | 24 ++++++++++++++++++++++ library/coretests/tests/num/uint_macros.rs | 23 +++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index dd7cdd79c0d60..92b920dd775ed 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -30,6 +30,7 @@ #![feature(duration_constructors)] #![feature(duration_constructors_lite)] #![feature(error_generic_member_access)] +#![feature(exact_div)] #![feature(exact_size_is_empty)] #![feature(extend_one)] #![feature(extern_types)] diff --git a/library/coretests/tests/num/int_macros.rs b/library/coretests/tests/num/int_macros.rs index 0d9fb9e797e1f..719d29e4e7cbc 100644 --- a/library/coretests/tests/num/int_macros.rs +++ b/library/coretests/tests/num/int_macros.rs @@ -683,5 +683,29 @@ macro_rules! int_module { assert_eq_const_safe!($T: <$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW3), 0); } } + + const EXACT_DIV_SUCCESS_DIVIDEND1: $T = 42; + const EXACT_DIV_SUCCESS_DIVISOR1: $T = 6; + const EXACT_DIV_SUCCESS_QUOTIENT1: $T = 7; + const EXACT_DIV_SUCCESS_DIVIDEND2: $T = 18; + const EXACT_DIV_SUCCESS_DIVISOR2: $T = 3; + const EXACT_DIV_SUCCESS_QUOTIENT2: $T = 6; + + test_runtime_and_compiletime! { + fn test_exact_div() { + // 42 / 6 + assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND1, EXACT_DIV_SUCCESS_DIVISOR1), Some(EXACT_DIV_SUCCESS_QUOTIENT1)); + assert_eq_const_safe!($T: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND1, EXACT_DIV_SUCCESS_DIVISOR1), EXACT_DIV_SUCCESS_QUOTIENT1); + + // 18 / 3 + assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND2, EXACT_DIV_SUCCESS_DIVISOR2), Some(EXACT_DIV_SUCCESS_QUOTIENT2)); + assert_eq_const_safe!($T: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND2, EXACT_DIV_SUCCESS_DIVISOR2), EXACT_DIV_SUCCESS_QUOTIENT2); + + // failures + assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(1, 2), None); + assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(<$T>::MIN, -1), None); + assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(0, 0), None); + } + } }; } diff --git a/library/coretests/tests/num/uint_macros.rs b/library/coretests/tests/num/uint_macros.rs index 2e35e8bf5342a..6f3d160964f14 100644 --- a/library/coretests/tests/num/uint_macros.rs +++ b/library/coretests/tests/num/uint_macros.rs @@ -516,5 +516,28 @@ macro_rules! uint_module { assert_eq_const_safe!($T: <$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW3), 0); } } + + const EXACT_DIV_SUCCESS_DIVIDEND1: $T = 42; + const EXACT_DIV_SUCCESS_DIVISOR1: $T = 6; + const EXACT_DIV_SUCCESS_QUOTIENT1: $T = 7; + const EXACT_DIV_SUCCESS_DIVIDEND2: $T = 18; + const EXACT_DIV_SUCCESS_DIVISOR2: $T = 3; + const EXACT_DIV_SUCCESS_QUOTIENT2: $T = 6; + + test_runtime_and_compiletime! { + fn test_exact_div() { + // 42 / 6 + assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND1, EXACT_DIV_SUCCESS_DIVISOR1), Some(EXACT_DIV_SUCCESS_QUOTIENT1)); + assert_eq_const_safe!($T: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND1, EXACT_DIV_SUCCESS_DIVISOR1), EXACT_DIV_SUCCESS_QUOTIENT1); + + // 18 / 3 + assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND2, EXACT_DIV_SUCCESS_DIVISOR2), Some(EXACT_DIV_SUCCESS_QUOTIENT2)); + assert_eq_const_safe!($T: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND2, EXACT_DIV_SUCCESS_DIVISOR2), EXACT_DIV_SUCCESS_QUOTIENT2); + + // failures + assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(1, 2), None); + assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(0, 0), None); + } + } }; } From 49969468b59287f905a001097de66ff9659b7b79 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Tue, 3 Jun 2025 09:54:30 +0200 Subject: [PATCH 11/17] Add missing 2015 edition directives These tests specifically test 2015 edition behavior, so ensure that they can only be run with this edition --- tests/ui/issues/issue-10806.rs | 1 + tests/ui/issues/issue-12729.rs | 1 + tests/ui/issues/issue-13105.rs | 1 + tests/ui/issues/issue-13775.rs | 1 + tests/ui/issues/issue-15774.rs | 1 + tests/ui/issues/issue-34074.rs | 1 + tests/ui/issues/issue-50571.fixed | 1 + tests/ui/issues/issue-50571.rs | 1 + tests/ui/issues/issue-50571.stderr | 2 +- tests/ui/issues/issue-86756.rs | 1 + tests/ui/issues/issue-86756.stderr | 10 +++++----- .../ui/lexer/lex-bad-str-literal-as-char-3.rs | 1 + ...x-bad-str-literal-as-char-3.rust2015.stderr | 2 +- ...x-bad-str-literal-as-char-3.rust2018.stderr | 2 +- ...x-bad-str-literal-as-char-3.rust2021.stderr | 4 ++-- .../ui/lifetimes/bare-trait-object-borrowck.rs | 4 +++- tests/ui/lifetimes/bare-trait-object.rs | 1 + tests/ui/lint/bare-trait-objects-path.rs | 1 + tests/ui/lint/bare-trait-objects-path.stderr | 10 +++++----- .../lint/lint-pre-expansion-extern-module.rs | 1 + tests/ui/lint/lint-qualification.fixed | 1 + tests/ui/lint/lint-qualification.rs | 1 + tests/ui/lint/lint-qualification.stderr | 18 +++++++++--------- .../use-redundant-prelude-rust-2015.rs | 1 + .../use-redundant-prelude-rust-2015.stderr | 10 +++++----- tests/ui/macros/try-macro.rs | 1 + tests/ui/parser/dyn-trait-compatibility.rs | 2 ++ tests/ui/parser/dyn-trait-compatibility.stderr | 16 ++++++++-------- tests/ui/parser/extern-crate-async.rs | 3 ++- tests/ui/parser/fn-field-parse-error-ice.rs | 1 + .../ui/parser/fn-field-parse-error-ice.stderr | 6 +++--- tests/ui/parser/issues/issue-114219.rs | 2 ++ tests/ui/parser/issues/issue-114219.stderr | 2 +- .../parser/recover-hrtb-before-dyn-impl-kw.rs | 2 ++ .../recover-hrtb-before-dyn-impl-kw.stderr | 6 +++--- tests/ui/proc-macro/trait-fn-args-2015.rs | 1 + 36 files changed, 74 insertions(+), 46 deletions(-) diff --git a/tests/ui/issues/issue-10806.rs b/tests/ui/issues/issue-10806.rs index 72d99ae3a795e..31315dc7c93a5 100644 --- a/tests/ui/issues/issue-10806.rs +++ b/tests/ui/issues/issue-10806.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ run-pass #![allow(unused_imports)] diff --git a/tests/ui/issues/issue-12729.rs b/tests/ui/issues/issue-12729.rs index 74014981df5de..4d45846bc6083 100644 --- a/tests/ui/issues/issue-12729.rs +++ b/tests/ui/issues/issue-12729.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ check-pass #![allow(dead_code)] diff --git a/tests/ui/issues/issue-13105.rs b/tests/ui/issues/issue-13105.rs index 0dd78372a2690..d119aa9c788d9 100644 --- a/tests/ui/issues/issue-13105.rs +++ b/tests/ui/issues/issue-13105.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ check-pass trait Foo { diff --git a/tests/ui/issues/issue-13775.rs b/tests/ui/issues/issue-13775.rs index 500ec6782a8b1..1477dab9e2158 100644 --- a/tests/ui/issues/issue-13775.rs +++ b/tests/ui/issues/issue-13775.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ check-pass trait Foo { diff --git a/tests/ui/issues/issue-15774.rs b/tests/ui/issues/issue-15774.rs index 8eb327a0d5e7a..dadd59cc077b1 100644 --- a/tests/ui/issues/issue-15774.rs +++ b/tests/ui/issues/issue-15774.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ run-pass #![deny(warnings)] diff --git a/tests/ui/issues/issue-34074.rs b/tests/ui/issues/issue-34074.rs index 9b3dee11d9b79..d642c74d412a4 100644 --- a/tests/ui/issues/issue-34074.rs +++ b/tests/ui/issues/issue-34074.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ check-pass // Make sure several unnamed function parameters don't conflict with each other diff --git a/tests/ui/issues/issue-50571.fixed b/tests/ui/issues/issue-50571.fixed index 37ed729be8168..6d73f17cca4ca 100644 --- a/tests/ui/issues/issue-50571.fixed +++ b/tests/ui/issues/issue-50571.fixed @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ run-rustfix #![allow(dead_code)] diff --git a/tests/ui/issues/issue-50571.rs b/tests/ui/issues/issue-50571.rs index 97a042d3ec1fb..dd840ffe4d170 100644 --- a/tests/ui/issues/issue-50571.rs +++ b/tests/ui/issues/issue-50571.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ run-rustfix #![allow(dead_code)] diff --git a/tests/ui/issues/issue-50571.stderr b/tests/ui/issues/issue-50571.stderr index 86709410670c1..9b00fe0f5db64 100644 --- a/tests/ui/issues/issue-50571.stderr +++ b/tests/ui/issues/issue-50571.stderr @@ -1,5 +1,5 @@ error[E0642]: patterns aren't allowed in methods without bodies - --> $DIR/issue-50571.rs:5:12 + --> $DIR/issue-50571.rs:6:12 | LL | fn foo([a, b]: [i32; 2]) {} | ^^^^^^ diff --git a/tests/ui/issues/issue-86756.rs b/tests/ui/issues/issue-86756.rs index 7f864eb285074..55a6c144839e8 100644 --- a/tests/ui/issues/issue-86756.rs +++ b/tests/ui/issues/issue-86756.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 trait Foo {} //~^ ERROR the name `T` is already used for a generic parameter in this item's generic parameters diff --git a/tests/ui/issues/issue-86756.stderr b/tests/ui/issues/issue-86756.stderr index 728d7ea709558..0f68b7648503c 100644 --- a/tests/ui/issues/issue-86756.stderr +++ b/tests/ui/issues/issue-86756.stderr @@ -1,5 +1,5 @@ error[E0403]: the name `T` is already used for a generic parameter in this item's generic parameters - --> $DIR/issue-86756.rs:1:14 + --> $DIR/issue-86756.rs:2:14 | LL | trait Foo {} | - ^ already used @@ -7,13 +7,13 @@ LL | trait Foo {} | first use of `T` error[E0412]: cannot find type `dyn` in this scope - --> $DIR/issue-86756.rs:5:10 + --> $DIR/issue-86756.rs:6:10 | LL | eq:: | ^^^ not found in this scope warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/issue-86756.rs:5:15 + --> $DIR/issue-86756.rs:6:15 | LL | eq:: | ^^^ @@ -27,13 +27,13 @@ LL | eq:: | +++ error[E0107]: missing generics for trait `Foo` - --> $DIR/issue-86756.rs:5:15 + --> $DIR/issue-86756.rs:6:15 | LL | eq:: | ^^^ expected at least 1 generic argument | note: trait defined here, with at least 1 generic parameter: `T` - --> $DIR/issue-86756.rs:1:7 + --> $DIR/issue-86756.rs:2:7 | LL | trait Foo {} | ^^^ - diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs index 52781d9c6d858..5b290899a70ba 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rs @@ -1,4 +1,5 @@ //@ revisions: rust2015 rust2018 rust2021 +//@[rust2015] edition:2015 //@[rust2018] edition:2018 //@[rust2021] edition:2021 fn main() { diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr index 2f92225de1fba..be3b114baf9ef 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2015.stderr @@ -1,5 +1,5 @@ error[E0762]: unterminated character literal - --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26 + --> $DIR/lex-bad-str-literal-as-char-3.rs:6:26 | LL | println!('hello world'); | ^^^ diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr index 2f92225de1fba..be3b114baf9ef 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2018.stderr @@ -1,5 +1,5 @@ error[E0762]: unterminated character literal - --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26 + --> $DIR/lex-bad-str-literal-as-char-3.rs:6:26 | LL | println!('hello world'); | ^^^ diff --git a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr index e10046e58e451..605cb66df1cf0 100644 --- a/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr +++ b/tests/ui/lexer/lex-bad-str-literal-as-char-3.rust2021.stderr @@ -1,5 +1,5 @@ error: prefix `world` is unknown - --> $DIR/lex-bad-str-literal-as-char-3.rs:5:21 + --> $DIR/lex-bad-str-literal-as-char-3.rs:6:21 | LL | println!('hello world'); | ^^^^^ unknown prefix @@ -12,7 +12,7 @@ LL + println!("hello world"); | error[E0762]: unterminated character literal - --> $DIR/lex-bad-str-literal-as-char-3.rs:5:26 + --> $DIR/lex-bad-str-literal-as-char-3.rs:6:26 | LL | println!('hello world'); | ^^^ diff --git a/tests/ui/lifetimes/bare-trait-object-borrowck.rs b/tests/ui/lifetimes/bare-trait-object-borrowck.rs index c54d3effffe52..4b81b66118a7a 100644 --- a/tests/ui/lifetimes/bare-trait-object-borrowck.rs +++ b/tests/ui/lifetimes/bare-trait-object-borrowck.rs @@ -1,5 +1,7 @@ -#![allow(bare_trait_objects)] +//@ edition: 2015 //@ check-pass +#![allow(bare_trait_objects)] + pub struct FormatWith<'a, I, F> { sep: &'a str, /// FormatWith uses interior mutability because Display::fmt takes &self. diff --git a/tests/ui/lifetimes/bare-trait-object.rs b/tests/ui/lifetimes/bare-trait-object.rs index 2feb8a880b1d9..e74f8ac03eab6 100644 --- a/tests/ui/lifetimes/bare-trait-object.rs +++ b/tests/ui/lifetimes/bare-trait-object.rs @@ -1,4 +1,5 @@ // Verify that lifetime resolution correctly accounts for `Fn` bare trait objects. +//@ edition: 2015 //@ check-pass #![allow(bare_trait_objects)] diff --git a/tests/ui/lint/bare-trait-objects-path.rs b/tests/ui/lint/bare-trait-objects-path.rs index 0e2294715cd8b..9643c48c9b8c1 100644 --- a/tests/ui/lint/bare-trait-objects-path.rs +++ b/tests/ui/lint/bare-trait-objects-path.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 #![feature(associated_type_defaults)] trait Assoc { diff --git a/tests/ui/lint/bare-trait-objects-path.stderr b/tests/ui/lint/bare-trait-objects-path.stderr index e611abd31f3b4..25f3e857806f2 100644 --- a/tests/ui/lint/bare-trait-objects-path.stderr +++ b/tests/ui/lint/bare-trait-objects-path.stderr @@ -1,5 +1,5 @@ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/bare-trait-objects-path.rs:14:5 + --> $DIR/bare-trait-objects-path.rs:15:5 | LL | Dyn::func(); | ^^^ @@ -13,7 +13,7 @@ LL | ::func(); | ++++ + warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/bare-trait-objects-path.rs:17:5 + --> $DIR/bare-trait-objects-path.rs:18:5 | LL | ::Dyn::func(); | ^^^^^ @@ -26,7 +26,7 @@ LL | ::func(); | ++++++ ++ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/bare-trait-objects-path.rs:20:5 + --> $DIR/bare-trait-objects-path.rs:21:5 | LL | Dyn::CONST; | ^^^ @@ -39,7 +39,7 @@ LL | ::CONST; | ++++ + warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/bare-trait-objects-path.rs:23:12 + --> $DIR/bare-trait-objects-path.rs:24:12 | LL | let _: Dyn::Ty; | ^^^ @@ -52,7 +52,7 @@ LL | let _: ::Ty; | ++++ + error[E0223]: ambiguous associated type - --> $DIR/bare-trait-objects-path.rs:23:12 + --> $DIR/bare-trait-objects-path.rs:24:12 | LL | let _: Dyn::Ty; | ^^^^^^^ diff --git a/tests/ui/lint/lint-pre-expansion-extern-module.rs b/tests/ui/lint/lint-pre-expansion-extern-module.rs index f1ab0cf3b7425..e85261befbc0b 100644 --- a/tests/ui/lint/lint-pre-expansion-extern-module.rs +++ b/tests/ui/lint/lint-pre-expansion-extern-module.rs @@ -1,5 +1,6 @@ //@ check-pass //@ compile-flags: -W rust-2018-compatibility +//@ edition: 2015 fn main() {} diff --git a/tests/ui/lint/lint-qualification.fixed b/tests/ui/lint/lint-qualification.fixed index 7c8fd5236e608..04067b6b6ff64 100644 --- a/tests/ui/lint/lint-qualification.fixed +++ b/tests/ui/lint/lint-qualification.fixed @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ run-rustfix #![deny(unused_qualifications)] #![deny(unused_imports)] diff --git a/tests/ui/lint/lint-qualification.rs b/tests/ui/lint/lint-qualification.rs index 009b3080d5c79..20c261bf87829 100644 --- a/tests/ui/lint/lint-qualification.rs +++ b/tests/ui/lint/lint-qualification.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ run-rustfix #![deny(unused_qualifications)] #![deny(unused_imports)] diff --git a/tests/ui/lint/lint-qualification.stderr b/tests/ui/lint/lint-qualification.stderr index cefa54a12ae10..1e8b8da1e86a5 100644 --- a/tests/ui/lint/lint-qualification.stderr +++ b/tests/ui/lint/lint-qualification.stderr @@ -1,11 +1,11 @@ error: unnecessary qualification - --> $DIR/lint-qualification.rs:12:5 + --> $DIR/lint-qualification.rs:13:5 | LL | foo::bar(); | ^^^^^^^^ | note: the lint level is defined here - --> $DIR/lint-qualification.rs:2:9 + --> $DIR/lint-qualification.rs:3:9 | LL | #![deny(unused_qualifications)] | ^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL + bar(); | error: unnecessary qualification - --> $DIR/lint-qualification.rs:13:5 + --> $DIR/lint-qualification.rs:14:5 | LL | crate::foo::bar(); | ^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL + bar(); | error: unnecessary qualification - --> $DIR/lint-qualification.rs:18:13 + --> $DIR/lint-qualification.rs:19:13 | LL | let _ = std::string::String::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL + let _ = String::new(); | error: unnecessary qualification - --> $DIR/lint-qualification.rs:20:12 + --> $DIR/lint-qualification.rs:21:12 | LL | let _: std::vec::Vec = std::vec::Vec::::new(); | ^^^^^^^^^^^^^^^^^^^^^ @@ -52,7 +52,7 @@ LL + let _: Vec = std::vec::Vec::::new(); | error: unnecessary qualification - --> $DIR/lint-qualification.rs:20:36 + --> $DIR/lint-qualification.rs:21:36 | LL | let _: std::vec::Vec = std::vec::Vec::::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,19 +64,19 @@ LL + let _: std::vec::Vec = Vec::::new(); | error: unused import: `std::fmt` - --> $DIR/lint-qualification.rs:24:9 + --> $DIR/lint-qualification.rs:25:9 | LL | use std::fmt; | ^^^^^^^^ | note: the lint level is defined here - --> $DIR/lint-qualification.rs:3:9 + --> $DIR/lint-qualification.rs:4:9 | LL | #![deny(unused_imports)] | ^^^^^^^^^^^^^^ error: unnecessary qualification - --> $DIR/lint-qualification.rs:29:13 + --> $DIR/lint-qualification.rs:30:13 | LL | let _ = ::default(); // issue #121999 (modified) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs index 6abe3602abee7..7dc9ba0afeae5 100644 --- a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs +++ b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ check-pass #![warn(redundant_imports)] diff --git a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr index 2b0e16a87dc06..48d5c275055f3 100644 --- a/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr +++ b/tests/ui/lint/use-redundant/use-redundant-prelude-rust-2015.stderr @@ -1,5 +1,5 @@ warning: the item `Some` is imported redundantly - --> $DIR/use-redundant-prelude-rust-2015.rs:5:5 + --> $DIR/use-redundant-prelude-rust-2015.rs:6:5 | LL | use std::option::Option::Some; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,13 +8,13 @@ LL | use std::option::Option::Some; = note: the item `Some` is already defined here | note: the lint level is defined here - --> $DIR/use-redundant-prelude-rust-2015.rs:2:9 + --> $DIR/use-redundant-prelude-rust-2015.rs:3:9 | LL | #![warn(redundant_imports)] | ^^^^^^^^^^^^^^^^^ warning: the item `None` is imported redundantly - --> $DIR/use-redundant-prelude-rust-2015.rs:6:5 + --> $DIR/use-redundant-prelude-rust-2015.rs:7:5 | LL | use std::option::Option::None; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | use std::option::Option::None; = note: the item `None` is already defined here warning: the item `Ok` is imported redundantly - --> $DIR/use-redundant-prelude-rust-2015.rs:8:5 + --> $DIR/use-redundant-prelude-rust-2015.rs:9:5 | LL | use std::result::Result::Ok; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | use std::result::Result::Ok; = note: the item `Ok` is already defined here warning: the item `Err` is imported redundantly - --> $DIR/use-redundant-prelude-rust-2015.rs:9:5 + --> $DIR/use-redundant-prelude-rust-2015.rs:10:5 | LL | use std::result::Result::Err; | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/macros/try-macro.rs b/tests/ui/macros/try-macro.rs index b579143583eb7..f6268654cfc17 100644 --- a/tests/ui/macros/try-macro.rs +++ b/tests/ui/macros/try-macro.rs @@ -1,4 +1,5 @@ //@ run-pass +//@ edition: 2015 #![allow(deprecated)] // for deprecated `try!()` macro use std::num::{ParseFloatError, ParseIntError}; diff --git a/tests/ui/parser/dyn-trait-compatibility.rs b/tests/ui/parser/dyn-trait-compatibility.rs index 717b14c5941fd..c6e84284fbec1 100644 --- a/tests/ui/parser/dyn-trait-compatibility.rs +++ b/tests/ui/parser/dyn-trait-compatibility.rs @@ -1,3 +1,5 @@ +//@ edition: 2015 + type A0 = dyn; //~^ ERROR cannot find type `dyn` in this scope type A1 = dyn::dyn; diff --git a/tests/ui/parser/dyn-trait-compatibility.stderr b/tests/ui/parser/dyn-trait-compatibility.stderr index 08e0a50010a88..a57c033c1e13d 100644 --- a/tests/ui/parser/dyn-trait-compatibility.stderr +++ b/tests/ui/parser/dyn-trait-compatibility.stderr @@ -1,47 +1,47 @@ error[E0412]: cannot find type `dyn` in this scope - --> $DIR/dyn-trait-compatibility.rs:1:11 + --> $DIR/dyn-trait-compatibility.rs:3:11 | LL | type A0 = dyn; | ^^^ not found in this scope error[E0412]: cannot find type `dyn` in this scope - --> $DIR/dyn-trait-compatibility.rs:5:11 + --> $DIR/dyn-trait-compatibility.rs:7:11 | LL | type A2 = dyn; | ^^^ not found in this scope error[E0412]: cannot find type `dyn` in this scope - --> $DIR/dyn-trait-compatibility.rs:5:15 + --> $DIR/dyn-trait-compatibility.rs:7:15 | LL | type A2 = dyn; | ^^^ not found in this scope error[E0412]: cannot find type `dyn` in this scope - --> $DIR/dyn-trait-compatibility.rs:5:20 + --> $DIR/dyn-trait-compatibility.rs:7:20 | LL | type A2 = dyn; | ^^^ not found in this scope error[E0412]: cannot find type `dyn` in this scope - --> $DIR/dyn-trait-compatibility.rs:9:11 + --> $DIR/dyn-trait-compatibility.rs:11:11 | LL | type A3 = dyn<::dyn>; | ^^^ not found in this scope error[E0405]: cannot find trait `dyn` in this scope - --> $DIR/dyn-trait-compatibility.rs:9:23 + --> $DIR/dyn-trait-compatibility.rs:11:23 | LL | type A3 = dyn<::dyn>; | ^^^ not found in this scope error[E0412]: cannot find type `dyn` in this scope - --> $DIR/dyn-trait-compatibility.rs:9:16 + --> $DIR/dyn-trait-compatibility.rs:11:16 | LL | type A3 = dyn<::dyn>; | ^^^ not found in this scope error[E0433]: failed to resolve: use of unresolved module or unlinked crate `dyn` - --> $DIR/dyn-trait-compatibility.rs:3:11 + --> $DIR/dyn-trait-compatibility.rs:5:11 | LL | type A1 = dyn::dyn; | ^^^ use of unresolved module or unlinked crate `dyn` diff --git a/tests/ui/parser/extern-crate-async.rs b/tests/ui/parser/extern-crate-async.rs index 529e0f1ab5cb8..13bd786d09219 100644 --- a/tests/ui/parser/extern-crate-async.rs +++ b/tests/ui/parser/extern-crate-async.rs @@ -1,6 +1,7 @@ -// Make sure that we don't parse `extern crate async` +// Make sure that we don't parse `extern crate async` as // the front matter of a function leading us astray. +//@ edition: 2015 //@ check-pass fn main() {} diff --git a/tests/ui/parser/fn-field-parse-error-ice.rs b/tests/ui/parser/fn-field-parse-error-ice.rs index 188257ea53a31..f1bc561b89fb7 100644 --- a/tests/ui/parser/fn-field-parse-error-ice.rs +++ b/tests/ui/parser/fn-field-parse-error-ice.rs @@ -1,4 +1,5 @@ // Regression test for #85794 +//@ edition: 2015 struct Baz { inner : dyn fn () diff --git a/tests/ui/parser/fn-field-parse-error-ice.stderr b/tests/ui/parser/fn-field-parse-error-ice.stderr index 3bf68e8cc04fe..6f033e2b0c6ff 100644 --- a/tests/ui/parser/fn-field-parse-error-ice.stderr +++ b/tests/ui/parser/fn-field-parse-error-ice.stderr @@ -1,11 +1,11 @@ error: expected `,`, or `}`, found keyword `fn` - --> $DIR/fn-field-parse-error-ice.rs:4:16 + --> $DIR/fn-field-parse-error-ice.rs:5:16 | LL | inner : dyn fn () | ^ help: try adding a comma: `,` error: expected identifier, found keyword `fn` - --> $DIR/fn-field-parse-error-ice.rs:4:17 + --> $DIR/fn-field-parse-error-ice.rs:5:17 | LL | struct Baz { | --- while parsing this struct @@ -18,7 +18,7 @@ LL | inner : dyn r#fn () | ++ error[E0412]: cannot find type `dyn` in this scope - --> $DIR/fn-field-parse-error-ice.rs:4:13 + --> $DIR/fn-field-parse-error-ice.rs:5:13 | LL | inner : dyn fn () | ^^^ not found in this scope diff --git a/tests/ui/parser/issues/issue-114219.rs b/tests/ui/parser/issues/issue-114219.rs index 332258b628c37..3f7e0f685acd2 100644 --- a/tests/ui/parser/issues/issue-114219.rs +++ b/tests/ui/parser/issues/issue-114219.rs @@ -1,3 +1,5 @@ +//@ edition: 2015 + fn main() { async move {}; //~^ ERROR `async move` blocks are only allowed in Rust 2018 or later diff --git a/tests/ui/parser/issues/issue-114219.stderr b/tests/ui/parser/issues/issue-114219.stderr index 02323cb99cbf3..1243ef8b1802b 100644 --- a/tests/ui/parser/issues/issue-114219.stderr +++ b/tests/ui/parser/issues/issue-114219.stderr @@ -1,5 +1,5 @@ error: `async move` blocks are only allowed in Rust 2018 or later - --> $DIR/issue-114219.rs:2:5 + --> $DIR/issue-114219.rs:4:5 | LL | async move {}; | ^^^^^^^^^^ diff --git a/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.rs b/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.rs index b9e3c5783ebd7..b78832bbe3dc0 100644 --- a/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.rs +++ b/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.rs @@ -1,3 +1,5 @@ +//@ edition: 2015 + trait Trait {} fn test(_: &for<'a> dyn Trait) {} diff --git a/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.stderr b/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.stderr index a012220e8c7c9..3745cf8b07790 100644 --- a/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.stderr +++ b/tests/ui/parser/recover-hrtb-before-dyn-impl-kw.stderr @@ -1,5 +1,5 @@ error: `for<...>` expected after `dyn`, not before - --> $DIR/recover-hrtb-before-dyn-impl-kw.rs:3:21 + --> $DIR/recover-hrtb-before-dyn-impl-kw.rs:5:21 | LL | fn test(_: &for<'a> dyn Trait) {} | ^^^ @@ -11,7 +11,7 @@ LL + fn test(_: &dyn for<'a> Trait) {} | error: `for<...>` expected after `impl`, not before - --> $DIR/recover-hrtb-before-dyn-impl-kw.rs:6:21 + --> $DIR/recover-hrtb-before-dyn-impl-kw.rs:8:21 | LL | fn test2(_: for<'a> impl Trait) {} | ^^^^ @@ -23,7 +23,7 @@ LL + fn test2(_: impl for<'a> Trait) {} | error: expected identifier, found `>` - --> $DIR/recover-hrtb-before-dyn-impl-kw.rs:10:24 + --> $DIR/recover-hrtb-before-dyn-impl-kw.rs:12:24 | LL | type A2 = dyn dyn>; | ^ expected identifier diff --git a/tests/ui/proc-macro/trait-fn-args-2015.rs b/tests/ui/proc-macro/trait-fn-args-2015.rs index c25bd768efe76..010d986a86df6 100644 --- a/tests/ui/proc-macro/trait-fn-args-2015.rs +++ b/tests/ui/proc-macro/trait-fn-args-2015.rs @@ -1,6 +1,7 @@ // Unnamed arguments in trait functions can be passed through proc macros on 2015 edition. //@ check-pass +//@ edition: 2015 //@ proc-macro: test-macros.rs #![allow(anonymous_parameters)] From 21a739fbf71ac118da144431f4c12b3714f875b9 Mon Sep 17 00:00:00 2001 From: Jeremy Smart Date: Tue, 3 Jun 2025 21:02:04 -0400 Subject: [PATCH 12/17] add tests for negative numbers --- library/coretests/tests/num/int_macros.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/library/coretests/tests/num/int_macros.rs b/library/coretests/tests/num/int_macros.rs index 719d29e4e7cbc..41d399c1ad9f5 100644 --- a/library/coretests/tests/num/int_macros.rs +++ b/library/coretests/tests/num/int_macros.rs @@ -690,6 +690,12 @@ macro_rules! int_module { const EXACT_DIV_SUCCESS_DIVIDEND2: $T = 18; const EXACT_DIV_SUCCESS_DIVISOR2: $T = 3; const EXACT_DIV_SUCCESS_QUOTIENT2: $T = 6; + const EXACT_DIV_SUCCESS_DIVIDEND3: $T = -91; + const EXACT_DIV_SUCCESS_DIVISOR3: $T = 13; + const EXACT_DIV_SUCCESS_QUOTIENT3: $T = -7; + const EXACT_DIV_SUCCESS_DIVIDEND4: $T = -57; + const EXACT_DIV_SUCCESS_DIVISOR4: $T = -3; + const EXACT_DIV_SUCCESS_QUOTIENT4: $T = 19; test_runtime_and_compiletime! { fn test_exact_div() { @@ -701,6 +707,14 @@ macro_rules! int_module { assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND2, EXACT_DIV_SUCCESS_DIVISOR2), Some(EXACT_DIV_SUCCESS_QUOTIENT2)); assert_eq_const_safe!($T: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND2, EXACT_DIV_SUCCESS_DIVISOR2), EXACT_DIV_SUCCESS_QUOTIENT2); + // -91 / 13 + assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND3, EXACT_DIV_SUCCESS_DIVISOR3), Some(EXACT_DIV_SUCCESS_QUOTIENT3)); + assert_eq_const_safe!($T: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND3, EXACT_DIV_SUCCESS_DIVISOR3), EXACT_DIV_SUCCESS_QUOTIENT3); + + // -57 / -3 + assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(EXACT_DIV_SUCCESS_DIVIDEND4, EXACT_DIV_SUCCESS_DIVISOR4), Some(EXACT_DIV_SUCCESS_QUOTIENT4)); + assert_eq_const_safe!($T: <$T>::exact_div(EXACT_DIV_SUCCESS_DIVIDEND4, EXACT_DIV_SUCCESS_DIVISOR4), EXACT_DIV_SUCCESS_QUOTIENT4); + // failures assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(1, 2), None); assert_eq_const_safe!(Option<$T>: <$T>::checked_exact_div(<$T>::MIN, -1), None); From bded7010e849680b56d897bcf32d09c999b98fd0 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 4 Jun 2025 06:57:12 +0300 Subject: [PATCH 13/17] run `check::Std` as the final step Signed-off-by: onur-ozkan --- src/bootstrap/src/core/builder/mod.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index af3e3cc37b928..19b79bfe818c2 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -945,7 +945,6 @@ impl<'a> Builder<'a> { clippy::CI, ), Kind::Check | Kind::Fix => describe!( - check::Std, check::Rustc, check::Rustdoc, check::CodegenBackend, @@ -961,6 +960,13 @@ impl<'a> Builder<'a> { check::Compiletest, check::FeaturesStatusDump, check::CoverageDump, + // This has special staging logic, it may run on stage 1 while others run on stage 0. + // It takes quite some time to build stage 1, so put this at the end. + // + // FIXME: This also helps bootstrap to not interfere with stage 0 builds. We should probably fix + // that issue somewhere else, but we still want to keep `check::Std` at the end so that the + // quicker steps run before this. + check::Std, ), Kind::Test => describe!( crate::core::build_steps::toolstate::ToolStateCheck, From e66948c4febb538ebd73b7f09733e947545fbf2c Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 4 Jun 2025 06:58:28 +0300 Subject: [PATCH 14/17] make it possible to request stage 0 std with `Builder::ensure` Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/check.rs | 34 ++++++++++++--------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 833cbedd5cf8e..a3bac5bfe7a8a 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -28,13 +28,16 @@ pub struct Std { /// passing `Builder::kind` to cargo invocations would run clippy on the entire compiler and library, /// which is not useful if we only want to lint a few crates with specific rules. override_build_kind: Option, + /// Never use this from outside calls. It is intended for internal use only within `check::Std::make_run` + /// and `check::Std::run`. + custom_stage: Option, } impl Std { const CRATE_OR_DEPS: &[&str] = &["sysroot", "coretests", "alloctests"]; pub fn new(target: TargetSelection) -> Self { - Self { target, crates: vec![], override_build_kind: None } + Self { target, crates: vec![], override_build_kind: None, custom_stage: None } } pub fn build_kind(mut self, kind: Option) -> Self { @@ -48,34 +51,35 @@ impl Step for Std { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - let builder = run.builder; - let stage = if builder.config.is_explicit_stage() || builder.top_stage >= 1 { - builder.top_stage - } else { - 1 - }; - let mut run = run; for c in Std::CRATE_OR_DEPS { run = run.crate_or_deps(c); } - run.path("library").default_condition(stage != 0) + run.path("library") } fn make_run(run: RunConfig<'_>) { let crates = std_crates_for_run_make(&run); - run.builder.ensure(Std { target: run.target, crates, override_build_kind: None }); + + let stage = if run.builder.config.is_explicit_stage() || run.builder.top_stage >= 1 { + run.builder.top_stage + } else { + 1 + }; + + run.builder.ensure(Std { + target: run.target, + crates, + override_build_kind: None, + custom_stage: Some(stage), + }); } fn run(self, builder: &Builder<'_>) { builder.require_submodule("library/stdarch", None); - let stage = if builder.config.is_explicit_stage() || builder.top_stage >= 1 { - builder.top_stage - } else { - 1 - }; + let stage = self.custom_stage.unwrap_or(builder.top_stage); let target = self.target; let compiler = builder.compiler(stage, builder.config.build); From 7af12a19a8b7362df651fee890db0db1ef8d2a17 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Wed, 4 Jun 2025 07:15:45 +0300 Subject: [PATCH 15/17] remove outdated RUSTC_SYSROOT handling for ci-rustc Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/test.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 22a458bac981c..dddce8fe05d1d 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2707,16 +2707,6 @@ impl Step for Crate { .arg(builder.src.join("library/sysroot/Cargo.toml")); } else { compile::std_cargo(builder, target, compiler.stage, &mut cargo); - // `std_cargo` actually does the wrong thing: it passes `--sysroot build/host/stage2`, - // but we want to use the force-recompile std we just built in `build/host/stage2-test-sysroot`. - // Override it. - if builder.download_rustc() && compiler.stage > 0 { - let sysroot = builder - .out - .join(compiler.host) - .join(format!("stage{}-test-sysroot", compiler.stage)); - cargo.env("RUSTC_SYSROOT", sysroot); - } } } Mode::Rustc => { From ed300d8ad881acc54f56a965e9c8f8a9e75a06d8 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 4 Jun 2025 16:40:00 +1000 Subject: [PATCH 16/17] Improve some `Visitor` comments. For AST/HIR/THIR visitors, explain the use of deconstruction. --- compiler/rustc_ast/src/visit.rs | 4 ++++ compiler/rustc_hir/src/intravisit.rs | 9 ++++----- compiler/rustc_middle/src/thir/visit.rs | 3 +++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 908d9fd4bdaec..1f7c97380dc27 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -121,6 +121,10 @@ pub enum LifetimeCtxt { /// explicitly, you need to override each method. (And you also need /// to monitor future changes to `Visitor` in case a new method with a /// new default implementation gets introduced.) +/// +/// Every `walk_*` method uses deconstruction to access fields of structs and +/// enums. This will result in a compile error if a field is added, which makes +/// it more likely the appropriate visit call will be added for it. pub trait Visitor<'ast>: Sized { /// The result type of the `visit_*` methods. Can be either `()`, /// or `ControlFlow`. diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index b9932a7334e13..42f6fb7aec1a7 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -200,6 +200,10 @@ use nested_filter::NestedFilter; /// explicitly, you need to override each method. (And you also need /// to monitor future changes to `Visitor` in case a new method with a /// new default implementation gets introduced.) +/// +/// Every `walk_*` method uses deconstruction to access fields of structs and +/// enums. This will result in a compile error if a field is added, which makes +/// it more likely the appropriate visit call will be added for it. pub trait Visitor<'v>: Sized { // This type should not be overridden, it exists for convenient usage as `Self::MaybeTyCtxt`. type MaybeTyCtxt: HirTyCtxt<'v> = >::MaybeTyCtxt; @@ -1201,7 +1205,6 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>( visitor: &mut V, trait_item: &'v TraitItem<'v>, ) -> V::Result { - // N.B., deliberately force a compilation error if/when new fields are added. let TraitItem { ident, generics, ref defaultness, ref kind, span, owner_id: _ } = *trait_item; let hir_id = trait_item.hir_id(); try_visit!(visitor.visit_ident(ident)); @@ -1240,7 +1243,6 @@ pub fn walk_trait_item_ref<'v, V: Visitor<'v>>( visitor: &mut V, trait_item_ref: &'v TraitItemRef, ) -> V::Result { - // N.B., deliberately force a compilation error if/when new fields are added. let TraitItemRef { id, ident, ref kind, span: _ } = *trait_item_ref; try_visit!(visitor.visit_nested_trait_item(id)); try_visit!(visitor.visit_ident(ident)); @@ -1251,7 +1253,6 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>( visitor: &mut V, impl_item: &'v ImplItem<'v>, ) -> V::Result { - // N.B., deliberately force a compilation error if/when new fields are added. let ImplItem { owner_id: _, ident, @@ -1286,7 +1287,6 @@ pub fn walk_foreign_item_ref<'v, V: Visitor<'v>>( visitor: &mut V, foreign_item_ref: &'v ForeignItemRef, ) -> V::Result { - // N.B., deliberately force a compilation error if/when new fields are added. let ForeignItemRef { id, ident, span: _ } = *foreign_item_ref; try_visit!(visitor.visit_nested_foreign_item(id)); visitor.visit_ident(ident) @@ -1296,7 +1296,6 @@ pub fn walk_impl_item_ref<'v, V: Visitor<'v>>( visitor: &mut V, impl_item_ref: &'v ImplItemRef, ) -> V::Result { - // N.B., deliberately force a compilation error if/when new fields are added. let ImplItemRef { id, ident, ref kind, span: _, trait_item_def_id: _ } = *impl_item_ref; try_visit!(visitor.visit_nested_impl_item(id)); try_visit!(visitor.visit_ident(ident)); diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 4da4dc3c02e70..d8743814d79c3 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -3,6 +3,9 @@ use super::{ Pat, PatKind, Stmt, StmtKind, Thir, }; +/// Every `walk_*` method uses deconstruction to access fields of structs and +/// enums. This will result in a compile error if a field is added, which makes +/// it more likely the appropriate visit call will be added for it. pub trait Visitor<'thir, 'tcx: 'thir>: Sized { fn thir(&self) -> &'thir Thir<'tcx>; From ccf9a89aa15d645f5e7eb391025075d09a6b3535 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Jun 2025 15:56:33 +0200 Subject: [PATCH 17/17] coretests: move float tests from num to floats module and use a more flexible macro to generate them --- library/coretests/tests/floats/mod.rs | 547 ++++++++++++++++++++++++++ library/coretests/tests/num/mod.rs | 353 ----------------- 2 files changed, 547 insertions(+), 353 deletions(-) diff --git a/library/coretests/tests/floats/mod.rs b/library/coretests/tests/floats/mod.rs index 7e27028a2a2d1..bd4bd07e4cb4c 100644 --- a/library/coretests/tests/floats/mod.rs +++ b/library/coretests/tests/floats/mod.rs @@ -52,6 +52,119 @@ macro_rules! assert_biteq { }; } +mod const_asserts { + // Shadow some assert implementations that would otherwise not compile in a const-context. + // Every macro added here also needs to be added in the `float_test!` macro below. + macro_rules! assert_eq { + ($left:expr, $right:expr $(,)?) => { + std::assert!($left == $right) + }; + ($left:expr, $right:expr, $($arg:tt)+) => { + std::assert!($left == $right, $($arg)+) + }; + } + + pub(crate) use assert_eq; +} + +/// Generate float tests for all our float types, for compile-time and run-time behavior. +/// +/// By default all tests run for all float types. Configuration can be applied via `attrs`. +/// +/// ```ignore (this is only a sketch) +/// float_test! { +/// name: fn_name, /* function under test */ +/// attrs: { +/// // Apply a configuration to the test for a single type +/// f16: #[cfg(target_has_reliable_f16_math)], +/// // Types can be excluded with `cfg(false)` +/// f64: #[cfg(false)], +/// }, +/// test { +/// /* write tests here, using `Float` as the type */ +/// } +/// } +macro_rules! float_test { + ( + name: $name:ident, + attrs: { + $(const: #[ $($const_meta:meta),+ ] ,)? + $(f16: #[ $($f16_meta:meta),+ ] ,)? + $(const f16: #[ $($f16_const_meta:meta),+ ] ,)? + $(f32: #[ $($f32_meta:meta),+ ] ,)? + $(const f32: #[ $($f32_const_meta:meta),+ ] ,)? + $(f64: #[ $($f64_meta:meta),+ ] ,)? + $(const f64: #[ $($f64_const_meta:meta),+ ] ,)? + $(f128: #[ $($f128_meta:meta),+ ] ,)? + $(const f128: #[ $($f128_const_meta:meta),+ ] ,)? + }, + test<$fty:ident> $test:block + ) => { + mod $name { + #[test] + $( $( #[$f16_meta] )+ )? + fn test_f16() { + type $fty = f16; + $test + } + + #[test] + $( $( #[$f32_meta] )+ )? + fn test_f32() { + type $fty = f32; + $test + } + + #[test] + $( $( #[$f64_meta] )+ )? + fn test_f64() { + type $fty = f64; + $test + } + + #[test] + $( $( #[$f128_meta] )+ )? + fn test_f128() { + type $fty = f128; + $test + } + + $( $( #[$const_meta] )+ )? + mod const_ { + use $crate::floats::const_asserts::assert_eq; + + #[test] + $( $( #[$f16_const_meta] )+ )? + fn test_f16() { + type $fty = f16; + const { $test } + } + + #[test] + $( $( #[$f32_const_meta] )+ )? + fn test_f32() { + type $fty = f32; + const { $test } + } + + #[test] + $( $( #[$f64_const_meta] )+ )? + fn test_f64() { + type $fty = f64; + const { $test } + } + + #[test] + $( $( #[$f128_const_meta] )+ )? + fn test_f128() { + type $fty = f128; + const { $test } + } + } + } + }; +} + /// Helper function for testing numeric operations pub fn test_num(ten: T, two: T) where @@ -75,3 +188,437 @@ mod f128; mod f16; mod f32; mod f64; + +float_test! { + name: min, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((0.0 as Float).min(0.0), 0.0); + assert!((0.0 as Float).min(0.0).is_sign_positive()); + assert_eq!((-0.0 as Float).min(-0.0), -0.0); + assert!((-0.0 as Float).min(-0.0).is_sign_negative()); + assert_eq!((9.0 as Float).min(9.0), 9.0); + assert_eq!((-9.0 as Float).min(0.0), -9.0); + assert_eq!((0.0 as Float).min(9.0), 0.0); + assert!((0.0 as Float).min(9.0).is_sign_positive()); + assert_eq!((-0.0 as Float).min(9.0), -0.0); + assert!((-0.0 as Float).min(9.0).is_sign_negative()); + assert_eq!((-0.0 as Float).min(-9.0), -9.0); + assert_eq!(Float::INFINITY.min(9.0), 9.0); + assert_eq!((9.0 as Float).min(Float::INFINITY), 9.0); + assert_eq!(Float::INFINITY.min(-9.0), -9.0); + assert_eq!((-9.0 as Float).min(Float::INFINITY), -9.0); + assert_eq!(Float::NEG_INFINITY.min(9.0), Float::NEG_INFINITY); + assert_eq!((9.0 as Float).min(Float::NEG_INFINITY), Float::NEG_INFINITY); + assert_eq!(Float::NEG_INFINITY.min(-9.0), Float::NEG_INFINITY); + assert_eq!((-9.0 as Float).min(Float::NEG_INFINITY), Float::NEG_INFINITY); + assert_eq!(Float::NAN.min(9.0), 9.0); + assert_eq!(Float::NAN.min(-9.0), -9.0); + assert_eq!((9.0 as Float).min(Float::NAN), 9.0); + assert_eq!((-9.0 as Float).min(Float::NAN), -9.0); + assert!(Float::NAN.min(Float::NAN).is_nan()); + } +} + +float_test! { + name: max, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((0.0 as Float).max(0.0), 0.0); + assert!((0.0 as Float).max(0.0).is_sign_positive()); + assert_eq!((-0.0 as Float).max(-0.0), -0.0); + assert!((-0.0 as Float).max(-0.0).is_sign_negative()); + assert_eq!((9.0 as Float).max(9.0), 9.0); + assert_eq!((-9.0 as Float).max(0.0), 0.0); + assert!((-9.0 as Float).max(0.0).is_sign_positive()); + assert_eq!((-9.0 as Float).max(-0.0), -0.0); + assert!((-9.0 as Float).max(-0.0).is_sign_negative()); + assert_eq!((0.0 as Float).max(9.0), 9.0); + assert_eq!((0.0 as Float).max(-9.0), 0.0); + assert!((0.0 as Float).max(-9.0).is_sign_positive()); + assert_eq!((-0.0 as Float).max(-9.0), -0.0); + assert!((-0.0 as Float).max(-9.0).is_sign_negative()); + assert_eq!(Float::INFINITY.max(9.0), Float::INFINITY); + assert_eq!((9.0 as Float).max(Float::INFINITY), Float::INFINITY); + assert_eq!(Float::INFINITY.max(-9.0), Float::INFINITY); + assert_eq!((-9.0 as Float).max(Float::INFINITY), Float::INFINITY); + assert_eq!(Float::NEG_INFINITY.max(9.0), 9.0); + assert_eq!((9.0 as Float).max(Float::NEG_INFINITY), 9.0); + assert_eq!(Float::NEG_INFINITY.max(-9.0), -9.0); + assert_eq!((-9.0 as Float).max(Float::NEG_INFINITY), -9.0); + assert_eq!(Float::NAN.max(9.0), 9.0); + assert_eq!(Float::NAN.max(-9.0), -9.0); + assert_eq!((9.0 as Float).max(Float::NAN), 9.0); + assert_eq!((-9.0 as Float).max(Float::NAN), -9.0); + assert!(Float::NAN.max(Float::NAN).is_nan()); + } +} + +float_test! { + name: minimum, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((0.0 as Float).minimum(0.0), 0.0); + assert!((0.0 as Float).minimum(0.0).is_sign_positive()); + assert_eq!((-0.0 as Float).minimum(0.0), -0.0); + assert!((-0.0 as Float).minimum(0.0).is_sign_negative()); + assert_eq!((-0.0 as Float).minimum(-0.0), -0.0); + assert!((-0.0 as Float).minimum(-0.0).is_sign_negative()); + assert_eq!((9.0 as Float).minimum(9.0), 9.0); + assert_eq!((-9.0 as Float).minimum(0.0), -9.0); + assert_eq!((0.0 as Float).minimum(9.0), 0.0); + assert!((0.0 as Float).minimum(9.0).is_sign_positive()); + assert_eq!((-0.0 as Float).minimum(9.0), -0.0); + assert!((-0.0 as Float).minimum(9.0).is_sign_negative()); + assert_eq!((-0.0 as Float).minimum(-9.0), -9.0); + assert_eq!(Float::INFINITY.minimum(9.0), 9.0); + assert_eq!((9.0 as Float).minimum(Float::INFINITY), 9.0); + assert_eq!(Float::INFINITY.minimum(-9.0), -9.0); + assert_eq!((-9.0 as Float).minimum(Float::INFINITY), -9.0); + assert_eq!(Float::NEG_INFINITY.minimum(9.0), Float::NEG_INFINITY); + assert_eq!((9.0 as Float).minimum(Float::NEG_INFINITY), Float::NEG_INFINITY); + assert_eq!(Float::NEG_INFINITY.minimum(-9.0), Float::NEG_INFINITY); + assert_eq!((-9.0 as Float).minimum(Float::NEG_INFINITY), Float::NEG_INFINITY); + assert!(Float::NAN.minimum(9.0).is_nan()); + assert!(Float::NAN.minimum(-9.0).is_nan()); + assert!((9.0 as Float).minimum(Float::NAN).is_nan()); + assert!((-9.0 as Float).minimum(Float::NAN).is_nan()); + assert!(Float::NAN.minimum(Float::NAN).is_nan()); + } +} + +float_test! { + name: maximum, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((0.0 as Float).maximum(0.0), 0.0); + assert!((0.0 as Float).maximum(0.0).is_sign_positive()); + assert_eq!((-0.0 as Float).maximum(0.0), 0.0); + assert!((-0.0 as Float).maximum(0.0).is_sign_positive()); + assert_eq!((-0.0 as Float).maximum(-0.0), -0.0); + assert!((-0.0 as Float).maximum(-0.0).is_sign_negative()); + assert_eq!((9.0 as Float).maximum(9.0), 9.0); + assert_eq!((-9.0 as Float).maximum(0.0), 0.0); + assert!((-9.0 as Float).maximum(0.0).is_sign_positive()); + assert_eq!((-9.0 as Float).maximum(-0.0), -0.0); + assert!((-9.0 as Float).maximum(-0.0).is_sign_negative()); + assert_eq!((0.0 as Float).maximum(9.0), 9.0); + assert_eq!((0.0 as Float).maximum(-9.0), 0.0); + assert!((0.0 as Float).maximum(-9.0).is_sign_positive()); + assert_eq!((-0.0 as Float).maximum(-9.0), -0.0); + assert!((-0.0 as Float).maximum(-9.0).is_sign_negative()); + assert_eq!(Float::INFINITY.maximum(9.0), Float::INFINITY); + assert_eq!((9.0 as Float).maximum(Float::INFINITY), Float::INFINITY); + assert_eq!(Float::INFINITY.maximum(-9.0), Float::INFINITY); + assert_eq!((-9.0 as Float).maximum(Float::INFINITY), Float::INFINITY); + assert_eq!(Float::NEG_INFINITY.maximum(9.0), 9.0); + assert_eq!((9.0 as Float).maximum(Float::NEG_INFINITY), 9.0); + assert_eq!(Float::NEG_INFINITY.maximum(-9.0), -9.0); + assert_eq!((-9.0 as Float).maximum(Float::NEG_INFINITY), -9.0); + assert!(Float::NAN.maximum(9.0).is_nan()); + assert!(Float::NAN.maximum(-9.0).is_nan()); + assert!((9.0 as Float).maximum(Float::NAN).is_nan()); + assert!((-9.0 as Float).maximum(Float::NAN).is_nan()); + assert!(Float::NAN.maximum(Float::NAN).is_nan()); + } +} + +float_test! { + name: midpoint, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((0.5 as Float).midpoint(0.5), 0.5); + assert_eq!((0.5 as Float).midpoint(2.5), 1.5); + assert_eq!((3.0 as Float).midpoint(4.0), 3.5); + assert_eq!((-3.0 as Float).midpoint(4.0), 0.5); + assert_eq!((3.0 as Float).midpoint(-4.0), -0.5); + assert_eq!((-3.0 as Float).midpoint(-4.0), -3.5); + assert_eq!((0.0 as Float).midpoint(0.0), 0.0); + assert_eq!((-0.0 as Float).midpoint(-0.0), -0.0); + assert_eq!((-5.0 as Float).midpoint(5.0), 0.0); + assert_eq!(Float::MAX.midpoint(Float::MIN), 0.0); + assert_eq!(Float::MIN.midpoint(Float::MAX), -0.0); + assert_eq!(Float::MAX.midpoint(Float::MIN_POSITIVE), Float::MAX / 2.); + assert_eq!((-Float::MAX).midpoint(Float::MIN_POSITIVE), -Float::MAX / 2.); + assert_eq!(Float::MAX.midpoint(-Float::MIN_POSITIVE), Float::MAX / 2.); + assert_eq!((-Float::MAX).midpoint(-Float::MIN_POSITIVE), -Float::MAX / 2.); + assert_eq!((Float::MIN_POSITIVE).midpoint(Float::MAX), Float::MAX / 2.); + assert_eq!((Float::MIN_POSITIVE).midpoint(-Float::MAX), -Float::MAX / 2.); + assert_eq!((-Float::MIN_POSITIVE).midpoint(Float::MAX), Float::MAX / 2.); + assert_eq!((-Float::MIN_POSITIVE).midpoint(-Float::MAX), -Float::MAX / 2.); + assert_eq!(Float::MAX.midpoint(Float::MAX), Float::MAX); + assert_eq!( + (Float::MIN_POSITIVE).midpoint(Float::MIN_POSITIVE), + Float::MIN_POSITIVE + ); + assert_eq!( + (-Float::MIN_POSITIVE).midpoint(-Float::MIN_POSITIVE), + -Float::MIN_POSITIVE + ); + assert_eq!(Float::MAX.midpoint(5.0), Float::MAX / 2.0 + 2.5); + assert_eq!(Float::MAX.midpoint(-5.0), Float::MAX / 2.0 - 2.5); + assert_eq!(Float::INFINITY.midpoint(Float::INFINITY), Float::INFINITY); + assert_eq!( + Float::NEG_INFINITY.midpoint(Float::NEG_INFINITY), + Float::NEG_INFINITY + ); + assert!(Float::NAN.midpoint(1.0).is_nan()); + assert!((1.0 as Float).midpoint(Float::NAN).is_nan()); + assert!(Float::NAN.midpoint(Float::NAN).is_nan()); + } +} + +// Separate test since the `for` loops cannot be run in `const`. +float_test! { + name: midpoint_large_magnitude, + attrs: { + const: #[cfg(false)], + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + // test if large differences in magnitude are still correctly computed. + // NOTE: that because of how small x and y are, x + y can never overflow + // so (x + y) / 2.0 is always correct + // in particular, `2.pow(i)` will never be at the max exponent, so it could + // be safely doubled, while j is significantly smaller. + for i in Float::MAX_EXP.saturating_sub(64)..Float::MAX_EXP { + for j in 0..64u8 { + let large = (2.0 as Float).powi(i); + // a much smaller number, such that there is no chance of overflow to test + // potential double rounding in midpoint's implementation. + let small = (2.0 as Float).powi(Float::MAX_EXP - 1) + * Float::EPSILON + * Float::from(j); + + let naive = (large + small) / 2.0; + let midpoint = large.midpoint(small); + + assert_eq!(naive, midpoint); + } + } + } +} + +float_test! { + name: abs, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((-1.0 as Float).abs(), 1.0); + assert_eq!((1.0 as Float).abs(), 1.0); + assert_eq!(Float::NEG_INFINITY.abs(), Float::INFINITY); + assert_eq!(Float::INFINITY.abs(), Float::INFINITY); + } +} + +float_test! { + name: copysign, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((1.0 as Float).copysign(-2.0), -1.0); + assert_eq!((-1.0 as Float).copysign(2.0), 1.0); + assert_eq!(Float::INFINITY.copysign(-0.0), Float::NEG_INFINITY); + assert_eq!(Float::NEG_INFINITY.copysign(0.0), Float::INFINITY); + } +} + +float_test! { + name: rem_euclid, + attrs: { + const: #[cfg(false)], + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert!(Float::INFINITY.rem_euclid(42.0 as Float).is_nan()); + assert_eq!((42.0 as Float).rem_euclid(Float::INFINITY), (42.0 as Float)); + assert!((42.0 as Float).rem_euclid(Float::NAN).is_nan()); + assert!(Float::INFINITY.rem_euclid(Float::INFINITY).is_nan()); + assert!(Float::INFINITY.rem_euclid(Float::NAN).is_nan()); + assert!(Float::NAN.rem_euclid(Float::INFINITY).is_nan()); + } +} + +float_test! { + name: div_euclid, + attrs: { + const: #[cfg(false)], + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((42.0 as Float).div_euclid(Float::INFINITY), 0.0); + assert!((42.0 as Float).div_euclid(Float::NAN).is_nan()); + assert!(Float::INFINITY.div_euclid(Float::INFINITY).is_nan()); + assert!(Float::INFINITY.div_euclid(Float::NAN).is_nan()); + assert!(Float::NAN.div_euclid(Float::INFINITY).is_nan()); + } +} + +float_test! { + name: floor, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((0.0 as Float).floor(), 0.0); + assert!((0.0 as Float).floor().is_sign_positive()); + assert_eq!((-0.0 as Float).floor(), -0.0); + assert!((-0.0 as Float).floor().is_sign_negative()); + assert_eq!((0.5 as Float).floor(), 0.0); + assert_eq!((-0.5 as Float).floor(), -1.0); + assert_eq!((1.5 as Float).floor(), 1.0); + assert_eq!(Float::MAX.floor(), Float::MAX); + assert_eq!(Float::MIN.floor(), Float::MIN); + assert_eq!(Float::MIN_POSITIVE.floor(), 0.0); + assert_eq!((-Float::MIN_POSITIVE).floor(), -1.0); + assert!(Float::NAN.floor().is_nan()); + assert_eq!(Float::INFINITY.floor(), Float::INFINITY); + assert_eq!(Float::NEG_INFINITY.floor(), Float::NEG_INFINITY); + } +} + +float_test! { + name: ceil, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((0.0 as Float).ceil(), 0.0); + assert!((0.0 as Float).ceil().is_sign_positive()); + assert_eq!((-0.0 as Float).ceil(), 0.0); + assert!((-0.0 as Float).ceil().is_sign_negative()); + assert_eq!((0.5 as Float).ceil(), 1.0); + assert_eq!((-0.5 as Float).ceil(), 0.0); + assert_eq!(Float::MAX.ceil(), Float::MAX); + assert_eq!(Float::MIN.ceil(), Float::MIN); + assert_eq!(Float::MIN_POSITIVE.ceil(), 1.0); + assert_eq!((-Float::MIN_POSITIVE).ceil(), 0.0); + assert!(Float::NAN.ceil().is_nan()); + assert_eq!(Float::INFINITY.ceil(), Float::INFINITY); + assert_eq!(Float::NEG_INFINITY.ceil(), Float::NEG_INFINITY); + } +} + +float_test! { + name: round, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((0.0 as Float).round(), 0.0); + assert!((0.0 as Float).round().is_sign_positive()); + assert_eq!((-0.0 as Float).round(), -0.0); + assert!((-0.0 as Float).round().is_sign_negative()); + assert_eq!((0.5 as Float).round(), 1.0); + assert_eq!((-0.5 as Float).round(), -1.0); + assert_eq!(Float::MAX.round(), Float::MAX); + assert_eq!(Float::MIN.round(), Float::MIN); + assert_eq!(Float::MIN_POSITIVE.round(), 0.0); + assert_eq!((-Float::MIN_POSITIVE).round(), 0.0); + assert!(Float::NAN.round().is_nan()); + assert_eq!(Float::INFINITY.round(), Float::INFINITY); + assert_eq!(Float::NEG_INFINITY.round(), Float::NEG_INFINITY); + } +} + +float_test! { + name: round_ties_even, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((0.0 as Float).round_ties_even(), 0.0); + assert!((0.0 as Float).round_ties_even().is_sign_positive()); + assert_eq!((-0.0 as Float).round_ties_even(), -0.0); + assert!((-0.0 as Float).round_ties_even().is_sign_negative()); + assert_eq!((0.5 as Float).round_ties_even(), 0.0); + assert!((0.5 as Float).round_ties_even().is_sign_positive()); + assert_eq!((-0.5 as Float).round_ties_even(), -0.0); + assert!((-0.5 as Float).round_ties_even().is_sign_negative()); + assert_eq!(Float::MAX.round_ties_even(), Float::MAX); + assert_eq!(Float::MIN.round_ties_even(), Float::MIN); + assert_eq!(Float::MIN_POSITIVE.round_ties_even(), 0.0); + assert_eq!((-Float::MIN_POSITIVE).round_ties_even(), 0.0); + assert!(Float::NAN.round_ties_even().is_nan()); + assert_eq!(Float::INFINITY.round_ties_even(), Float::INFINITY); + assert_eq!(Float::NEG_INFINITY.round_ties_even(), Float::NEG_INFINITY); + } +} + +float_test! { + name: trunc, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((0.0 as Float).trunc(), 0.0); + assert!((0.0 as Float).trunc().is_sign_positive()); + assert_eq!((-0.0 as Float).trunc(), -0.0); + assert!((-0.0 as Float).trunc().is_sign_negative()); + assert_eq!((0.5 as Float).trunc(), 0.0); + assert!((0.5 as Float).trunc().is_sign_positive()); + assert_eq!((-0.5 as Float).trunc(), -0.0); + assert!((-0.5 as Float).trunc().is_sign_negative()); + assert_eq!(Float::MAX.trunc(), Float::MAX); + assert_eq!(Float::MIN.trunc(), Float::MIN); + assert_eq!(Float::MIN_POSITIVE.trunc(), 0.0); + assert_eq!((-Float::MIN_POSITIVE).trunc(), 0.0); + assert!(Float::NAN.trunc().is_nan()); + assert_eq!(Float::INFINITY.trunc(), Float::INFINITY); + assert_eq!(Float::NEG_INFINITY.trunc(), Float::NEG_INFINITY); + } +} + +float_test! { + name: fract, + attrs: { + f16: #[cfg(any(miri, target_has_reliable_f16_math))], + f128: #[cfg(any(miri, target_has_reliable_f128_math))], + }, + test { + assert_eq!((0.0 as Float).fract(), 0.0); + assert!((0.0 as Float).fract().is_sign_positive()); + assert_eq!((-0.0 as Float).fract(), 0.0); + assert!((-0.0 as Float).fract().is_sign_positive()); + assert_eq!((0.5 as Float).fract(), 0.5); + assert!((0.5 as Float).fract().is_sign_positive()); + assert_eq!((-0.5 as Float).fract(), -0.5); + assert!((-0.5 as Float).fract().is_sign_negative()); + assert_eq!(Float::MAX.fract(), 0.0); + assert_eq!(Float::MIN.fract(), 0.0); + assert_eq!(Float::MIN_POSITIVE.fract(), Float::MIN_POSITIVE); + assert!(Float::MIN_POSITIVE.fract().is_sign_positive()); + assert_eq!((-Float::MIN_POSITIVE).fract(), -Float::MIN_POSITIVE); + assert!((-Float::MIN_POSITIVE).fract().is_sign_negative()); + assert!(Float::NAN.fract().is_nan()); + assert!(Float::INFINITY.fract().is_nan()); + assert!(Float::NEG_INFINITY.fract().is_nan()); + } +} diff --git a/library/coretests/tests/num/mod.rs b/library/coretests/tests/num/mod.rs index c68b569f86b3a..6611aa57866ff 100644 --- a/library/coretests/tests/num/mod.rs +++ b/library/coretests/tests/num/mod.rs @@ -730,356 +730,3 @@ assume_usize_width! { } } } - -// FIXME(141726): there is a lot of duplication between the following tests and -// the tests in `coretests/tests/floats/f*.rs` -// See issue https://github.com/rust-lang/rust/issues/141726 for more details. -macro_rules! test_float { - ($modname: ident, $fassert: ident, $fty: ty) => { - mod $modname { - #[test] - fn min() { - $fassert!((0.0 as $fty).min(0.0), 0.0); - $fassert!((0.0 as $fty).min(0.0).is_sign_positive()); - $fassert!((-0.0 as $fty).min(-0.0), -0.0); - $fassert!((-0.0 as $fty).min(-0.0).is_sign_negative()); - $fassert!((9.0 as $fty).min(9.0), 9.0); - $fassert!((-9.0 as $fty).min(0.0), -9.0); - $fassert!((0.0 as $fty).min(9.0), 0.0); - $fassert!((0.0 as $fty).min(9.0).is_sign_positive()); - $fassert!((-0.0 as $fty).min(9.0), -0.0); - $fassert!((-0.0 as $fty).min(9.0).is_sign_negative()); - $fassert!((-0.0 as $fty).min(-9.0), -9.0); - $fassert!(<$fty>::INFINITY.min(9.0), 9.0); - $fassert!((9.0 as $fty).min(<$fty>::INFINITY), 9.0); - $fassert!(<$fty>::INFINITY.min(-9.0), -9.0); - $fassert!((-9.0 as $fty).min(<$fty>::INFINITY), -9.0); - $fassert!(<$fty>::NEG_INFINITY.min(9.0), <$fty>::NEG_INFINITY); - $fassert!((9.0 as $fty).min(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); - $fassert!(<$fty>::NEG_INFINITY.min(-9.0), <$fty>::NEG_INFINITY); - $fassert!((-9.0 as $fty).min(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); - $fassert!(<$fty>::NAN.min(9.0), 9.0); - $fassert!(<$fty>::NAN.min(-9.0), -9.0); - $fassert!((9.0 as $fty).min(<$fty>::NAN), 9.0); - $fassert!((-9.0 as $fty).min(<$fty>::NAN), -9.0); - $fassert!(<$fty>::NAN.min(<$fty>::NAN).is_nan()); - } - #[test] - fn max() { - $fassert!((0.0 as $fty).max(0.0), 0.0); - $fassert!((0.0 as $fty).max(0.0).is_sign_positive()); - $fassert!((-0.0 as $fty).max(-0.0), -0.0); - $fassert!((-0.0 as $fty).max(-0.0).is_sign_negative()); - $fassert!((9.0 as $fty).max(9.0), 9.0); - $fassert!((-9.0 as $fty).max(0.0), 0.0); - $fassert!((-9.0 as $fty).max(0.0).is_sign_positive()); - $fassert!((-9.0 as $fty).max(-0.0), -0.0); - $fassert!((-9.0 as $fty).max(-0.0).is_sign_negative()); - $fassert!((0.0 as $fty).max(9.0), 9.0); - $fassert!((0.0 as $fty).max(-9.0), 0.0); - $fassert!((0.0 as $fty).max(-9.0).is_sign_positive()); - $fassert!((-0.0 as $fty).max(-9.0), -0.0); - $fassert!((-0.0 as $fty).max(-9.0).is_sign_negative()); - $fassert!(<$fty>::INFINITY.max(9.0), <$fty>::INFINITY); - $fassert!((9.0 as $fty).max(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!(<$fty>::INFINITY.max(-9.0), <$fty>::INFINITY); - $fassert!((-9.0 as $fty).max(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!(<$fty>::NEG_INFINITY.max(9.0), 9.0); - $fassert!((9.0 as $fty).max(<$fty>::NEG_INFINITY), 9.0); - $fassert!(<$fty>::NEG_INFINITY.max(-9.0), -9.0); - $fassert!((-9.0 as $fty).max(<$fty>::NEG_INFINITY), -9.0); - $fassert!(<$fty>::NAN.max(9.0), 9.0); - $fassert!(<$fty>::NAN.max(-9.0), -9.0); - $fassert!((9.0 as $fty).max(<$fty>::NAN), 9.0); - $fassert!((-9.0 as $fty).max(<$fty>::NAN), -9.0); - $fassert!(<$fty>::NAN.max(<$fty>::NAN).is_nan()); - } - #[test] - fn minimum() { - $fassert!((0.0 as $fty).minimum(0.0), 0.0); - $fassert!((0.0 as $fty).minimum(0.0).is_sign_positive()); - $fassert!((-0.0 as $fty).minimum(0.0), -0.0); - $fassert!((-0.0 as $fty).minimum(0.0).is_sign_negative()); - $fassert!((-0.0 as $fty).minimum(-0.0), -0.0); - $fassert!((-0.0 as $fty).minimum(-0.0).is_sign_negative()); - $fassert!((9.0 as $fty).minimum(9.0), 9.0); - $fassert!((-9.0 as $fty).minimum(0.0), -9.0); - $fassert!((0.0 as $fty).minimum(9.0), 0.0); - $fassert!((0.0 as $fty).minimum(9.0).is_sign_positive()); - $fassert!((-0.0 as $fty).minimum(9.0), -0.0); - $fassert!((-0.0 as $fty).minimum(9.0).is_sign_negative()); - $fassert!((-0.0 as $fty).minimum(-9.0), -9.0); - $fassert!(<$fty>::INFINITY.minimum(9.0), 9.0); - $fassert!((9.0 as $fty).minimum(<$fty>::INFINITY), 9.0); - $fassert!(<$fty>::INFINITY.minimum(-9.0), -9.0); - $fassert!((-9.0 as $fty).minimum(<$fty>::INFINITY), -9.0); - $fassert!(<$fty>::NEG_INFINITY.minimum(9.0), <$fty>::NEG_INFINITY); - $fassert!((9.0 as $fty).minimum(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); - $fassert!(<$fty>::NEG_INFINITY.minimum(-9.0), <$fty>::NEG_INFINITY); - $fassert!((-9.0 as $fty).minimum(<$fty>::NEG_INFINITY), <$fty>::NEG_INFINITY); - $fassert!(<$fty>::NAN.minimum(9.0).is_nan()); - $fassert!(<$fty>::NAN.minimum(-9.0).is_nan()); - $fassert!((9.0 as $fty).minimum(<$fty>::NAN).is_nan()); - $fassert!((-9.0 as $fty).minimum(<$fty>::NAN).is_nan()); - $fassert!(<$fty>::NAN.minimum(<$fty>::NAN).is_nan()); - } - #[test] - fn maximum() { - $fassert!((0.0 as $fty).maximum(0.0), 0.0); - $fassert!((0.0 as $fty).maximum(0.0).is_sign_positive()); - $fassert!((-0.0 as $fty).maximum(0.0), 0.0); - $fassert!((-0.0 as $fty).maximum(0.0).is_sign_positive()); - $fassert!((-0.0 as $fty).maximum(-0.0), -0.0); - $fassert!((-0.0 as $fty).maximum(-0.0).is_sign_negative()); - $fassert!((9.0 as $fty).maximum(9.0), 9.0); - $fassert!((-9.0 as $fty).maximum(0.0), 0.0); - $fassert!((-9.0 as $fty).maximum(0.0).is_sign_positive()); - $fassert!((-9.0 as $fty).maximum(-0.0), -0.0); - $fassert!((-9.0 as $fty).maximum(-0.0).is_sign_negative()); - $fassert!((0.0 as $fty).maximum(9.0), 9.0); - $fassert!((0.0 as $fty).maximum(-9.0), 0.0); - $fassert!((0.0 as $fty).maximum(-9.0).is_sign_positive()); - $fassert!((-0.0 as $fty).maximum(-9.0), -0.0); - $fassert!((-0.0 as $fty).maximum(-9.0).is_sign_negative()); - $fassert!(<$fty>::INFINITY.maximum(9.0), <$fty>::INFINITY); - $fassert!((9.0 as $fty).maximum(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!(<$fty>::INFINITY.maximum(-9.0), <$fty>::INFINITY); - $fassert!((-9.0 as $fty).maximum(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!(<$fty>::NEG_INFINITY.maximum(9.0), 9.0); - $fassert!((9.0 as $fty).maximum(<$fty>::NEG_INFINITY), 9.0); - $fassert!(<$fty>::NEG_INFINITY.maximum(-9.0), -9.0); - $fassert!((-9.0 as $fty).maximum(<$fty>::NEG_INFINITY), -9.0); - $fassert!(<$fty>::NAN.maximum(9.0).is_nan()); - $fassert!(<$fty>::NAN.maximum(-9.0).is_nan()); - $fassert!((9.0 as $fty).maximum(<$fty>::NAN).is_nan()); - $fassert!((-9.0 as $fty).maximum(<$fty>::NAN).is_nan()); - $fassert!(<$fty>::NAN.maximum(<$fty>::NAN).is_nan()); - } - #[test] - fn midpoint() { - $fassert!((0.5 as $fty).midpoint(0.5), 0.5); - $fassert!((0.5 as $fty).midpoint(2.5), 1.5); - $fassert!((3.0 as $fty).midpoint(4.0), 3.5); - $fassert!((-3.0 as $fty).midpoint(4.0), 0.5); - $fassert!((3.0 as $fty).midpoint(-4.0), -0.5); - $fassert!((-3.0 as $fty).midpoint(-4.0), -3.5); - $fassert!((0.0 as $fty).midpoint(0.0), 0.0); - $fassert!((-0.0 as $fty).midpoint(-0.0), -0.0); - $fassert!((-5.0 as $fty).midpoint(5.0), 0.0); - $fassert!(<$fty>::MAX.midpoint(<$fty>::MIN), 0.0); - $fassert!(<$fty>::MIN.midpoint(<$fty>::MAX), -0.0); - $fassert!(<$fty>::MAX.midpoint(<$fty>::MIN_POSITIVE), <$fty>::MAX / 2.); - $fassert!((-<$fty>::MAX).midpoint(<$fty>::MIN_POSITIVE), -<$fty>::MAX / 2.); - $fassert!(<$fty>::MAX.midpoint(-<$fty>::MIN_POSITIVE), <$fty>::MAX / 2.); - $fassert!((-<$fty>::MAX).midpoint(-<$fty>::MIN_POSITIVE), -<$fty>::MAX / 2.); - $fassert!((<$fty>::MIN_POSITIVE).midpoint(<$fty>::MAX), <$fty>::MAX / 2.); - $fassert!((<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MAX), -<$fty>::MAX / 2.); - $fassert!((-<$fty>::MIN_POSITIVE).midpoint(<$fty>::MAX), <$fty>::MAX / 2.); - $fassert!((-<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MAX), -<$fty>::MAX / 2.); - $fassert!(<$fty>::MAX.midpoint(<$fty>::MAX), <$fty>::MAX); - $fassert!( - (<$fty>::MIN_POSITIVE).midpoint(<$fty>::MIN_POSITIVE), - <$fty>::MIN_POSITIVE - ); - $fassert!( - (-<$fty>::MIN_POSITIVE).midpoint(-<$fty>::MIN_POSITIVE), - -<$fty>::MIN_POSITIVE - ); - $fassert!(<$fty>::MAX.midpoint(5.0), <$fty>::MAX / 2.0 + 2.5); - $fassert!(<$fty>::MAX.midpoint(-5.0), <$fty>::MAX / 2.0 - 2.5); - $fassert!(<$fty>::INFINITY.midpoint(<$fty>::INFINITY), <$fty>::INFINITY); - $fassert!( - <$fty>::NEG_INFINITY.midpoint(<$fty>::NEG_INFINITY), - <$fty>::NEG_INFINITY - ); - $fassert!(<$fty>::NAN.midpoint(1.0).is_nan()); - $fassert!((1.0 as $fty).midpoint(<$fty>::NAN).is_nan()); - $fassert!(<$fty>::NAN.midpoint(<$fty>::NAN).is_nan()); - - // test if large differences in magnitude are still correctly computed. - // NOTE: that because of how small x and y are, x + y can never overflow - // so (x + y) / 2.0 is always correct - // in particular, `2.pow(i)` will never be at the max exponent, so it could - // be safely doubled, while j is significantly smaller. - for i in <$fty>::MAX_EXP.saturating_sub(64)..<$fty>::MAX_EXP { - for j in 0..64u8 { - let large = (2.0 as $fty).powi(i); - // a much smaller number, such that there is no chance of overflow to test - // potential double rounding in midpoint's implementation. - let small = (2.0 as $fty).powi(<$fty>::MAX_EXP - 1) - * <$fty>::EPSILON - * <$fty>::from(j); - - let naive = (large + small) / 2.0; - let midpoint = large.midpoint(small); - - assert_eq!(naive, midpoint); - } - } - } - #[test] - fn abs() { - $fassert!((-1.0 as $fty).abs(), 1.0); - $fassert!((1.0 as $fty).abs(), 1.0); - $fassert!(<$fty>::NEG_INFINITY.abs(), <$fty>::INFINITY); - $fassert!(<$fty>::INFINITY.abs(), <$fty>::INFINITY); - } - #[test] - fn copysign() { - $fassert!((1.0 as $fty).copysign(-2.0), -1.0); - $fassert!((-1.0 as $fty).copysign(2.0), 1.0); - $fassert!(<$fty>::INFINITY.copysign(-0.0), <$fty>::NEG_INFINITY); - $fassert!(<$fty>::NEG_INFINITY.copysign(0.0), <$fty>::INFINITY); - } - #[test] - fn rem_euclid() { - // FIXME: Use $fassert when rem_euclid becomes const - assert!(<$fty>::INFINITY.rem_euclid((42.0 as $fty)).is_nan()); - assert_eq!((42.0 as $fty).rem_euclid(<$fty>::INFINITY), (42.0 as $fty)); - assert!((42.0 as $fty).rem_euclid(<$fty>::NAN).is_nan()); - assert!(<$fty>::INFINITY.rem_euclid(<$fty>::INFINITY).is_nan()); - assert!(<$fty>::INFINITY.rem_euclid(<$fty>::NAN).is_nan()); - assert!(<$fty>::NAN.rem_euclid(<$fty>::INFINITY).is_nan()); - } - #[test] - fn div_euclid() { - // FIXME: Use $fassert when div_euclid becomes const - assert_eq!((42.0 as $fty).div_euclid(<$fty>::INFINITY), 0.0); - assert!((42.0 as $fty).div_euclid(<$fty>::NAN).is_nan()); - assert!(<$fty>::INFINITY.div_euclid(<$fty>::INFINITY).is_nan()); - assert!(<$fty>::INFINITY.div_euclid(<$fty>::NAN).is_nan()); - assert!(<$fty>::NAN.div_euclid(<$fty>::INFINITY).is_nan()); - } - #[test] - fn floor() { - $fassert!((0.0 as $fty).floor(), 0.0); - $fassert!((0.0 as $fty).floor().is_sign_positive()); - $fassert!((-0.0 as $fty).floor(), -0.0); - $fassert!((-0.0 as $fty).floor().is_sign_negative()); - $fassert!((0.5 as $fty).floor(), 0.0); - $fassert!((-0.5 as $fty).floor(), -1.0); - $fassert!((1.5 as $fty).floor(), 1.0); - $fassert!(<$fty>::MAX.floor(), <$fty>::MAX); - $fassert!(<$fty>::MIN.floor(), <$fty>::MIN); - $fassert!(<$fty>::MIN_POSITIVE.floor(), 0.0); - $fassert!((-<$fty>::MIN_POSITIVE).floor(), -1.0); - $fassert!(<$fty>::NAN.floor().is_nan()); - $fassert!(<$fty>::INFINITY.floor(), <$fty>::INFINITY); - $fassert!(<$fty>::NEG_INFINITY.floor(), <$fty>::NEG_INFINITY); - } - #[test] - fn ceil() { - $fassert!((0.0 as $fty).ceil(), 0.0); - $fassert!((0.0 as $fty).ceil().is_sign_positive()); - $fassert!((-0.0 as $fty).ceil(), 0.0); - $fassert!((-0.0 as $fty).ceil().is_sign_negative()); - $fassert!((0.5 as $fty).ceil(), 1.0); - $fassert!((-0.5 as $fty).ceil(), 0.0); - $fassert!(<$fty>::MAX.ceil(), <$fty>::MAX); - $fassert!(<$fty>::MIN.ceil(), <$fty>::MIN); - $fassert!(<$fty>::MIN_POSITIVE.ceil(), 1.0); - $fassert!((-<$fty>::MIN_POSITIVE).ceil(), 0.0); - $fassert!(<$fty>::NAN.ceil().is_nan()); - $fassert!(<$fty>::INFINITY.ceil(), <$fty>::INFINITY); - $fassert!(<$fty>::NEG_INFINITY.ceil(), <$fty>::NEG_INFINITY); - } - #[test] - fn round() { - $fassert!((0.0 as $fty).round(), 0.0); - $fassert!((0.0 as $fty).round().is_sign_positive()); - $fassert!((-0.0 as $fty).round(), -0.0); - $fassert!((-0.0 as $fty).round().is_sign_negative()); - $fassert!((0.5 as $fty).round(), 1.0); - $fassert!((-0.5 as $fty).round(), -1.0); - $fassert!(<$fty>::MAX.round(), <$fty>::MAX); - $fassert!(<$fty>::MIN.round(), <$fty>::MIN); - $fassert!(<$fty>::MIN_POSITIVE.round(), 0.0); - $fassert!((-<$fty>::MIN_POSITIVE).round(), 0.0); - $fassert!(<$fty>::NAN.round().is_nan()); - $fassert!(<$fty>::INFINITY.round(), <$fty>::INFINITY); - $fassert!(<$fty>::NEG_INFINITY.round(), <$fty>::NEG_INFINITY); - } - #[test] - fn round_ties_even() { - $fassert!((0.0 as $fty).round_ties_even(), 0.0); - $fassert!((0.0 as $fty).round_ties_even().is_sign_positive()); - $fassert!((-0.0 as $fty).round_ties_even(), -0.0); - $fassert!((-0.0 as $fty).round_ties_even().is_sign_negative()); - $fassert!((0.5 as $fty).round_ties_even(), 0.0); - $fassert!((0.5 as $fty).round_ties_even().is_sign_positive()); - $fassert!((-0.5 as $fty).round_ties_even(), -0.0); - $fassert!((-0.5 as $fty).round_ties_even().is_sign_negative()); - $fassert!(<$fty>::MAX.round_ties_even(), <$fty>::MAX); - $fassert!(<$fty>::MIN.round_ties_even(), <$fty>::MIN); - $fassert!(<$fty>::MIN_POSITIVE.round_ties_even(), 0.0); - $fassert!((-<$fty>::MIN_POSITIVE).round_ties_even(), 0.0); - $fassert!(<$fty>::NAN.round_ties_even().is_nan()); - $fassert!(<$fty>::INFINITY.round_ties_even(), <$fty>::INFINITY); - $fassert!(<$fty>::NEG_INFINITY.round_ties_even(), <$fty>::NEG_INFINITY); - } - #[test] - fn trunc() { - $fassert!((0.0 as $fty).trunc(), 0.0); - $fassert!((0.0 as $fty).trunc().is_sign_positive()); - $fassert!((-0.0 as $fty).trunc(), -0.0); - $fassert!((-0.0 as $fty).trunc().is_sign_negative()); - $fassert!((0.5 as $fty).trunc(), 0.0); - $fassert!((0.5 as $fty).trunc().is_sign_positive()); - $fassert!((-0.5 as $fty).trunc(), -0.0); - $fassert!((-0.5 as $fty).trunc().is_sign_negative()); - $fassert!(<$fty>::MAX.trunc(), <$fty>::MAX); - $fassert!(<$fty>::MIN.trunc(), <$fty>::MIN); - $fassert!(<$fty>::MIN_POSITIVE.trunc(), 0.0); - $fassert!((-<$fty>::MIN_POSITIVE).trunc(), 0.0); - $fassert!(<$fty>::NAN.trunc().is_nan()); - $fassert!(<$fty>::INFINITY.trunc(), <$fty>::INFINITY); - $fassert!(<$fty>::NEG_INFINITY.trunc(), <$fty>::NEG_INFINITY); - } - #[test] - fn fract() { - $fassert!((0.0 as $fty).fract(), 0.0); - $fassert!((0.0 as $fty).fract().is_sign_positive()); - $fassert!((-0.0 as $fty).fract(), 0.0); - $fassert!((-0.0 as $fty).fract().is_sign_positive()); - $fassert!((0.5 as $fty).fract(), 0.5); - $fassert!((0.5 as $fty).fract().is_sign_positive()); - $fassert!((-0.5 as $fty).fract(), -0.5); - $fassert!((-0.5 as $fty).fract().is_sign_negative()); - $fassert!(<$fty>::MAX.fract(), 0.0); - $fassert!(<$fty>::MIN.fract(), 0.0); - $fassert!(<$fty>::MIN_POSITIVE.fract(), <$fty>::MIN_POSITIVE); - $fassert!(<$fty>::MIN_POSITIVE.fract().is_sign_positive()); - $fassert!((-<$fty>::MIN_POSITIVE).fract(), -<$fty>::MIN_POSITIVE); - $fassert!((-<$fty>::MIN_POSITIVE).fract().is_sign_negative()); - $fassert!(<$fty>::NAN.fract().is_nan()); - $fassert!(<$fty>::INFINITY.fract().is_nan()); - $fassert!(<$fty>::NEG_INFINITY.fract().is_nan()); - } - } - }; -} - -// Custom assert macro that distribute between assert! and assert_eq! in a non-const context -macro_rules! float_assert { - ($b:expr) => { - assert!($b); - }; - ($left:expr, $right:expr) => { - assert_eq!($left, $right); - }; -} - -// Custom assert macro that only uses assert! in a const context -macro_rules! float_const_assert { - ($b:expr) => { - assert!(const { $b }); - }; - ($left:expr, $right:expr) => { - assert!(const { $left == $right }); - }; -} - -test_float!(f32, float_assert, f32); -test_float!(f32_const, float_const_assert, f32); -test_float!(f64, float_assert, f64); -test_float!(f64_const, float_const_assert, f64);