From df27dfa0eae8a14d69e5006334bb06d84ba050b7 Mon Sep 17 00:00:00 2001 From: Mikhail Zabaluev Date: Fri, 22 Mar 2024 16:50:48 +0200 Subject: [PATCH 01/14] Optimize integer pow by removing exit branch The branch at the end of the `pow` implementations is redundant with multiplication code already present in the loop. By rotating the exit check, this branch can be largely removed, improving code size and instruction cache coherence. --- library/core/src/num/int_macros.rs | 61 ++++++++++++--------------- library/core/src/num/uint_macros.rs | 64 ++++++++++++----------------- 2 files changed, 52 insertions(+), 73 deletions(-) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index d40e02352a1d0..6ed0eb07e48d8 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1495,18 +1495,17 @@ macro_rules! int_impl { let mut base = self; let mut acc: Self = 1; - while exp > 1 { + loop { if (exp & 1) == 1 { acc = try_opt!(acc.checked_mul(base)); + // since exp!=0, finally the exp must be 1. + if exp == 1 { + return Some(acc); + } } exp /= 2; base = try_opt!(base.checked_mul(base)); } - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - acc.checked_mul(base) } /// Strict exponentiation. Computes `self.pow(exp)`, panicking if @@ -1546,18 +1545,17 @@ macro_rules! int_impl { let mut base = self; let mut acc: Self = 1; - while exp > 1 { + loop { if (exp & 1) == 1 { acc = acc.strict_mul(base); + // since exp!=0, finally the exp must be 1. + if exp == 1 { + return acc; + } } exp /= 2; base = base.strict_mul(base); } - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - acc.strict_mul(base) } /// Returns the square root of the number, rounded down. @@ -2181,19 +2179,17 @@ macro_rules! int_impl { let mut base = self; let mut acc: Self = 1; - while exp > 1 { + loop { if (exp & 1) == 1 { acc = acc.wrapping_mul(base); + // since exp!=0, finally the exp must be 1. + if exp == 1 { + return acc; + } } exp /= 2; base = base.wrapping_mul(base); } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - acc.wrapping_mul(base) } /// Calculates `self` + `rhs` @@ -2687,9 +2683,14 @@ macro_rules! int_impl { // Scratch space for storing results of overflowing_mul. let mut r; - while exp > 1 { + loop { if (exp & 1) == 1 { r = acc.overflowing_mul(base); + // since exp!=0, finally the exp must be 1. + if exp == 1 { + r.1 |= overflown; + return r; + } acc = r.0; overflown |= r.1; } @@ -2698,14 +2699,6 @@ macro_rules! int_impl { base = r.0; overflown |= r.1; } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - r = acc.overflowing_mul(base); - r.1 |= overflown; - r } /// Raises self to the power of `exp`, using exponentiation by squaring. @@ -2732,19 +2725,17 @@ macro_rules! int_impl { let mut base = self; let mut acc = 1; - while exp > 1 { + loop { if (exp & 1) == 1 { acc = acc * base; + // since exp!=0, finally the exp must be 1. + if exp == 1 { + return acc; + } } exp /= 2; base = base * base; } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - acc * base } /// Returns the square root of the number, rounded down. diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index ad72c29758bd7..b272a9d901bf4 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1534,20 +1534,17 @@ macro_rules! uint_impl { let mut base = self; let mut acc: Self = 1; - while exp > 1 { + loop { if (exp & 1) == 1 { acc = try_opt!(acc.checked_mul(base)); + // since exp!=0, finally the exp must be 1. + if exp == 1 { + return Some(acc); + } } exp /= 2; base = try_opt!(base.checked_mul(base)); } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - - acc.checked_mul(base) } /// Strict exponentiation. Computes `self.pow(exp)`, panicking if @@ -1587,18 +1584,17 @@ macro_rules! uint_impl { let mut base = self; let mut acc: Self = 1; - while exp > 1 { + loop { if (exp & 1) == 1 { acc = acc.strict_mul(base); + // since exp!=0, finally the exp must be 1. + if exp == 1 { + return acc; + } } exp /= 2; base = base.strict_mul(base); } - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - acc.strict_mul(base) } /// Saturating integer addition. Computes `self + rhs`, saturating at @@ -2059,19 +2055,17 @@ macro_rules! uint_impl { let mut base = self; let mut acc: Self = 1; - while exp > 1 { + loop { if (exp & 1) == 1 { acc = acc.wrapping_mul(base); + // since exp!=0, finally the exp must be 1. + if exp == 1 { + return acc; + } } exp /= 2; base = base.wrapping_mul(base); } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - acc.wrapping_mul(base) } /// Calculates `self` + `rhs` @@ -2516,9 +2510,14 @@ macro_rules! uint_impl { // Scratch space for storing results of overflowing_mul. let mut r; - while exp > 1 { + loop { if (exp & 1) == 1 { r = acc.overflowing_mul(base); + // since exp!=0, finally the exp must be 1. + if exp == 1 { + r.1 |= overflown; + return r; + } acc = r.0; overflown |= r.1; } @@ -2527,15 +2526,6 @@ macro_rules! uint_impl { base = r.0; overflown |= r.1; } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - r = acc.overflowing_mul(base); - r.1 |= overflown; - - r } /// Raises self to the power of `exp`, using exponentiation by squaring. @@ -2560,19 +2550,17 @@ macro_rules! uint_impl { let mut base = self; let mut acc = 1; - while exp > 1 { + loop { if (exp & 1) == 1 { acc = acc * base; + // since exp!=0, finally the exp must be 1. + if exp == 1 { + return acc; + } } exp /= 2; base = base * base; } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - acc * base } /// Returns the square root of the number, rounded down. From 1faa1018c7ddd2f505904b0f71255afa5ae1bbe7 Mon Sep 17 00:00:00 2001 From: Mikhail Zabaluev Date: Fri, 12 Jul 2024 00:54:26 +0300 Subject: [PATCH 02/14] Explicitly unroll integer pow for small exponents The newly optimized loop has introduced a regression in the case when pow is called with a small constant exponent. LLVM is no longer able to unroll the loop and the generated code is larger and slower than what's expected in tests. Match and handle small exponent values separately by branching out to an explicit multiplication sequence for that exponent. Powers larger than 6 need more than three multiplications, so these cases are less likely to benefit from this optimization, also such constant exponents are less likely to be used in practice. For uses with a non-constant exponent, this might also provide a performance benefit if the exponent is small and does not vary between successive calls, so the same match arm tends to be taken as a predicted branch. --- library/core/src/num/int_macros.rs | 62 ++++++++++++++++++++++++++--- library/core/src/num/uint_macros.rs | 62 ++++++++++++++++++++++++++--- 2 files changed, 112 insertions(+), 12 deletions(-) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 6ed0eb07e48d8..d1bb5a6ef478a 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -2173,10 +2173,35 @@ macro_rules! int_impl { without modifying the original"] #[inline] pub const fn wrapping_pow(self, mut exp: u32) -> Self { - if exp == 0 { - return 1; - } let mut base = self; + + // Unroll multiplications for small exponent values. + // This gives the optimizer a way to efficiently inline call sites + // for the most common use cases with constant exponents. + // Currently, LLVM is unable to unroll the loop below. + match exp { + 0 => return 1, + 1 => return base, + 2 => return base.wrapping_mul(base), + 3 => { + let squared = base.wrapping_mul(base); + return squared.wrapping_mul(base); + } + 4 => { + let squared = base.wrapping_mul(base); + return squared.wrapping_mul(squared); + } + 5 => { + let squared = base.wrapping_mul(base); + return squared.wrapping_mul(squared).wrapping_mul(base); + } + 6 => { + let cubed = base.wrapping_mul(base).wrapping_mul(base); + return cubed.wrapping_mul(cubed); + } + _ => {} + } + let mut acc: Self = 1; loop { @@ -2719,10 +2744,35 @@ macro_rules! int_impl { #[inline] #[rustc_inherit_overflow_checks] pub const fn pow(self, mut exp: u32) -> Self { - if exp == 0 { - return 1; - } let mut base = self; + + // Unroll multiplications for small exponent values. + // This gives the optimizer a way to efficiently inline call sites + // for the most common use cases with constant exponents. + // Currently, LLVM is unable to unroll the loop below. + match exp { + 0 => return 1, + 1 => return base, + 2 => return base * base, + 3 => { + let squared = base * base; + return squared * base; + } + 4 => { + let squared = base * base; + return squared * squared; + } + 5 => { + let squared = base * base; + return squared * squared * base; + } + 6 => { + let cubed = base * base * base; + return cubed * cubed; + } + _ => {} + } + let mut acc = 1; loop { diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index b272a9d901bf4..6e5d37f8163ea 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -2049,10 +2049,35 @@ macro_rules! uint_impl { without modifying the original"] #[inline] pub const fn wrapping_pow(self, mut exp: u32) -> Self { - if exp == 0 { - return 1; - } let mut base = self; + + // Unroll multiplications for small exponent values. + // This gives the optimizer a way to efficiently inline call sites + // for the most common use cases with constant exponents. + // Currently, LLVM is unable to unroll the loop below. + match exp { + 0 => return 1, + 1 => return base, + 2 => return base.wrapping_mul(base), + 3 => { + let squared = base.wrapping_mul(base); + return squared.wrapping_mul(base); + } + 4 => { + let squared = base.wrapping_mul(base); + return squared.wrapping_mul(squared); + } + 5 => { + let squared = base.wrapping_mul(base); + return squared.wrapping_mul(squared).wrapping_mul(base); + } + 6 => { + let cubed = base.wrapping_mul(base).wrapping_mul(base); + return cubed.wrapping_mul(cubed); + } + _ => {} + } + let mut acc: Self = 1; loop { @@ -2544,10 +2569,35 @@ macro_rules! uint_impl { #[inline] #[rustc_inherit_overflow_checks] pub const fn pow(self, mut exp: u32) -> Self { - if exp == 0 { - return 1; - } let mut base = self; + + // Unroll multiplications for small exponent values. + // This gives the optimizer a way to efficiently inline call sites + // for the most common use cases with constant exponents. + // Currently, LLVM is unable to unroll the loop below. + match exp { + 0 => return 1, + 1 => return base, + 2 => return base * base, + 3 => { + let squared = base * base; + return squared * base; + } + 4 => { + let squared = base * base; + return squared * squared; + } + 5 => { + let squared = base * base; + return squared * squared * base; + } + 6 => { + let cubed = base * base * base; + return cubed * cubed; + } + _ => {} + } + let mut acc = 1; loop { From 2f235343529c39bdab47704ec9620d6784eeeb6d Mon Sep 17 00:00:00 2001 From: Mikhail Zabaluev Date: Fri, 12 Jul 2024 22:54:08 +0300 Subject: [PATCH 03/14] Use is_val_statically_known to optimize pow In the dynamic exponent case, it's preferred to not increase code size, so use solely the loop-based implementation there. This shows about 4% penalty in the variable exponent benchmarks on x86_64. --- library/core/src/lib.rs | 1 + library/core/src/num/int_macros.rs | 108 ++++++++++++++++------------ library/core/src/num/uint_macros.rs | 108 ++++++++++++++++------------ 3 files changed, 125 insertions(+), 92 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 0f82f01e57a71..ede95e3b2ca9b 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -170,6 +170,7 @@ #![feature(internal_impls_macro)] #![feature(ip)] #![feature(is_ascii_octdigit)] +#![feature(is_val_statically_known)] #![feature(isqrt)] #![feature(link_cfg)] #![feature(offset_of_enum)] diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index d1bb5a6ef478a..be0e6a2a03b70 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -2172,35 +2172,43 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[rustc_allow_const_fn_unstable(is_val_statically_known)] pub const fn wrapping_pow(self, mut exp: u32) -> Self { let mut base = self; - // Unroll multiplications for small exponent values. - // This gives the optimizer a way to efficiently inline call sites - // for the most common use cases with constant exponents. - // Currently, LLVM is unable to unroll the loop below. - match exp { - 0 => return 1, - 1 => return base, - 2 => return base.wrapping_mul(base), - 3 => { - let squared = base.wrapping_mul(base); - return squared.wrapping_mul(base); - } - 4 => { - let squared = base.wrapping_mul(base); - return squared.wrapping_mul(squared); - } - 5 => { - let squared = base.wrapping_mul(base); - return squared.wrapping_mul(squared).wrapping_mul(base); + if intrinsics::is_val_statically_known(exp) { + // Unroll multiplications for small exponent values. + // This gives the optimizer a way to efficiently inline call sites + // for the most common use cases with constant exponents. + // Currently, LLVM is unable to unroll the loop below. + match exp { + 0 => return 1, + 1 => return base, + 2 => return base.wrapping_mul(base), + 3 => { + let squared = base.wrapping_mul(base); + return squared.wrapping_mul(base); + } + 4 => { + let squared = base.wrapping_mul(base); + return squared.wrapping_mul(squared); + } + 5 => { + let squared = base.wrapping_mul(base); + return squared.wrapping_mul(squared).wrapping_mul(base); + } + 6 => { + let cubed = base.wrapping_mul(base).wrapping_mul(base); + return cubed.wrapping_mul(cubed); + } + _ => {} } - 6 => { - let cubed = base.wrapping_mul(base).wrapping_mul(base); - return cubed.wrapping_mul(cubed); + } else { + if exp == 0 { + return 1; } - _ => {} } + debug_assert!(exp != 0); let mut acc: Self = 1; @@ -2743,35 +2751,43 @@ macro_rules! int_impl { without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] + #[rustc_allow_const_fn_unstable(is_val_statically_known)] pub const fn pow(self, mut exp: u32) -> Self { let mut base = self; - // Unroll multiplications for small exponent values. - // This gives the optimizer a way to efficiently inline call sites - // for the most common use cases with constant exponents. - // Currently, LLVM is unable to unroll the loop below. - match exp { - 0 => return 1, - 1 => return base, - 2 => return base * base, - 3 => { - let squared = base * base; - return squared * base; - } - 4 => { - let squared = base * base; - return squared * squared; - } - 5 => { - let squared = base * base; - return squared * squared * base; + if intrinsics::is_val_statically_known(exp) { + // Unroll multiplications for small exponent values. + // This gives the optimizer a way to efficiently inline call sites + // for the most common use cases with constant exponents. + // Currently, LLVM is unable to unroll the loop below. + match exp { + 0 => return 1, + 1 => return base, + 2 => return base * base, + 3 => { + let squared = base * base; + return squared * base; + } + 4 => { + let squared = base * base; + return squared * squared; + } + 5 => { + let squared = base * base; + return squared * squared * base; + } + 6 => { + let cubed = base * base * base; + return cubed * cubed; + } + _ => {} } - 6 => { - let cubed = base * base * base; - return cubed * cubed; + } else { + if exp == 0 { + return 1; } - _ => {} } + debug_assert!(exp != 0); let mut acc = 1; diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 6e5d37f8163ea..24352593fca3d 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -2048,35 +2048,43 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] + #[rustc_allow_const_fn_unstable(is_val_statically_known)] pub const fn wrapping_pow(self, mut exp: u32) -> Self { let mut base = self; - // Unroll multiplications for small exponent values. - // This gives the optimizer a way to efficiently inline call sites - // for the most common use cases with constant exponents. - // Currently, LLVM is unable to unroll the loop below. - match exp { - 0 => return 1, - 1 => return base, - 2 => return base.wrapping_mul(base), - 3 => { - let squared = base.wrapping_mul(base); - return squared.wrapping_mul(base); - } - 4 => { - let squared = base.wrapping_mul(base); - return squared.wrapping_mul(squared); - } - 5 => { - let squared = base.wrapping_mul(base); - return squared.wrapping_mul(squared).wrapping_mul(base); + if intrinsics::is_val_statically_known(exp) { + // Unroll multiplications for small exponent values. + // This gives the optimizer a way to efficiently inline call sites + // for the most common use cases with constant exponents. + // Currently, LLVM is unable to unroll the loop below. + match exp { + 0 => return 1, + 1 => return base, + 2 => return base.wrapping_mul(base), + 3 => { + let squared = base.wrapping_mul(base); + return squared.wrapping_mul(base); + } + 4 => { + let squared = base.wrapping_mul(base); + return squared.wrapping_mul(squared); + } + 5 => { + let squared = base.wrapping_mul(base); + return squared.wrapping_mul(squared).wrapping_mul(base); + } + 6 => { + let cubed = base.wrapping_mul(base).wrapping_mul(base); + return cubed.wrapping_mul(cubed); + } + _ => {} } - 6 => { - let cubed = base.wrapping_mul(base).wrapping_mul(base); - return cubed.wrapping_mul(cubed); + } else { + if exp == 0 { + return 1; } - _ => {} } + debug_assert!(exp != 0); let mut acc: Self = 1; @@ -2568,35 +2576,43 @@ macro_rules! uint_impl { without modifying the original"] #[inline] #[rustc_inherit_overflow_checks] + #[rustc_allow_const_fn_unstable(is_val_statically_known)] pub const fn pow(self, mut exp: u32) -> Self { let mut base = self; - // Unroll multiplications for small exponent values. - // This gives the optimizer a way to efficiently inline call sites - // for the most common use cases with constant exponents. - // Currently, LLVM is unable to unroll the loop below. - match exp { - 0 => return 1, - 1 => return base, - 2 => return base * base, - 3 => { - let squared = base * base; - return squared * base; - } - 4 => { - let squared = base * base; - return squared * squared; - } - 5 => { - let squared = base * base; - return squared * squared * base; + if intrinsics::is_val_statically_known(exp) { + // Unroll multiplications for small exponent values. + // This gives the optimizer a way to efficiently inline call sites + // for the most common use cases with constant exponents. + // Currently, LLVM is unable to unroll the loop below. + match exp { + 0 => return 1, + 1 => return base, + 2 => return base * base, + 3 => { + let squared = base * base; + return squared * base; + } + 4 => { + let squared = base * base; + return squared * squared; + } + 5 => { + let squared = base * base; + return squared * squared * base; + } + 6 => { + let cubed = base * base * base; + return cubed * cubed; + } + _ => {} } - 6 => { - let cubed = base * base * base; - return cubed * cubed; + } else { + if exp == 0 { + return 1; } - _ => {} } + debug_assert!(exp != 0); let mut acc = 1; From 1e445f48d4d0880d4c158c3ae96be8f0d9ad2e02 Mon Sep 17 00:00:00 2001 From: Henry Sloan Date: Mon, 12 Aug 2024 18:48:03 -0700 Subject: [PATCH 04/14] Add must_use attribute to Coroutine trait --- library/core/src/ops/coroutine.rs | 1 + tests/ui/coroutine/issue-58888.rs | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/library/core/src/ops/coroutine.rs b/library/core/src/ops/coroutine.rs index 13df888d24c5c..c7d596d74c383 100644 --- a/library/core/src/ops/coroutine.rs +++ b/library/core/src/ops/coroutine.rs @@ -69,6 +69,7 @@ pub enum CoroutineState { #[lang = "coroutine"] #[unstable(feature = "coroutine_trait", issue = "43122")] #[fundamental] +#[must_use = "coroutines are lazy and do nothing unless resumed"] pub trait Coroutine { /// The type of value this coroutine yields. /// diff --git a/tests/ui/coroutine/issue-58888.rs b/tests/ui/coroutine/issue-58888.rs index 6266f97ce8c46..e4fada0cd432e 100644 --- a/tests/ui/coroutine/issue-58888.rs +++ b/tests/ui/coroutine/issue-58888.rs @@ -13,7 +13,8 @@ impl Database { } fn check_connection(&self) -> impl Coroutine + '_ { - #[coroutine] move || { + #[coroutine] + move || { let iter = self.get_connection(); for i in iter { yield i @@ -23,5 +24,5 @@ impl Database { } fn main() { - Database.check_connection(); + let _ = Database.check_connection(); } From ac88b330b875e8058589b1804ac5d95fcd40905d Mon Sep 17 00:00:00 2001 From: Mikhail Zabaluev Date: Tue, 13 Aug 2024 08:21:16 +0300 Subject: [PATCH 05/14] Revert to original loop for const pow exponents Give LLVM the for original, optimizable loop in pow and wrapped_pow functions in the case when the exponent is statically known. --- library/core/src/num/int_macros.rs | 135 ++++++++++++---------------- library/core/src/num/uint_macros.rs | 135 ++++++++++++---------------- 2 files changed, 110 insertions(+), 160 deletions(-) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index be0e6a2a03b70..d8ef36f21ac63 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -2174,54 +2174,41 @@ macro_rules! int_impl { #[inline] #[rustc_allow_const_fn_unstable(is_val_statically_known)] pub const fn wrapping_pow(self, mut exp: u32) -> Self { + if exp == 0 { + return 1; + } let mut base = self; + let mut acc: Self = 1; if intrinsics::is_val_statically_known(exp) { - // Unroll multiplications for small exponent values. - // This gives the optimizer a way to efficiently inline call sites - // for the most common use cases with constant exponents. - // Currently, LLVM is unable to unroll the loop below. - match exp { - 0 => return 1, - 1 => return base, - 2 => return base.wrapping_mul(base), - 3 => { - let squared = base.wrapping_mul(base); - return squared.wrapping_mul(base); - } - 4 => { - let squared = base.wrapping_mul(base); - return squared.wrapping_mul(squared); + while exp > 1 { + if (exp & 1) == 1 { + acc = acc.wrapping_mul(base); } - 5 => { - let squared = base.wrapping_mul(base); - return squared.wrapping_mul(squared).wrapping_mul(base); - } - 6 => { - let cubed = base.wrapping_mul(base).wrapping_mul(base); - return cubed.wrapping_mul(cubed); - } - _ => {} + exp /= 2; + base = base.wrapping_mul(base); } - } else { - if exp == 0 { - return 1; - } - } - debug_assert!(exp != 0); - let mut acc: Self = 1; - - loop { - if (exp & 1) == 1 { - acc = acc.wrapping_mul(base); - // since exp!=0, finally the exp must be 1. - if exp == 1 { - return acc; + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary. + acc.wrapping_mul(base) + } else { + // This is faster than the above when the exponent is not known + // at compile time. We can't use the same code for the constant + // exponent case because LLVM is currently unable to unroll + // this loop. + loop { + if (exp & 1) == 1 { + acc = acc.wrapping_mul(base); + // since exp!=0, finally the exp must be 1. + if exp == 1 { + return acc; + } } + exp /= 2; + base = base.wrapping_mul(base); } - exp /= 2; - base = base.wrapping_mul(base); } } @@ -2753,54 +2740,42 @@ macro_rules! int_impl { #[rustc_inherit_overflow_checks] #[rustc_allow_const_fn_unstable(is_val_statically_known)] pub const fn pow(self, mut exp: u32) -> Self { + if exp == 0 { + return 1; + } let mut base = self; + let mut acc = 1; if intrinsics::is_val_statically_known(exp) { - // Unroll multiplications for small exponent values. - // This gives the optimizer a way to efficiently inline call sites - // for the most common use cases with constant exponents. - // Currently, LLVM is unable to unroll the loop below. - match exp { - 0 => return 1, - 1 => return base, - 2 => return base * base, - 3 => { - let squared = base * base; - return squared * base; - } - 4 => { - let squared = base * base; - return squared * squared; + while exp > 1 { + if (exp & 1) == 1 { + acc = acc * base; } - 5 => { - let squared = base * base; - return squared * squared * base; - } - 6 => { - let cubed = base * base * base; - return cubed * cubed; - } - _ => {} + exp /= 2; + base = base * base; } - } else { - if exp == 0 { - return 1; - } - } - debug_assert!(exp != 0); - let mut acc = 1; - - loop { - if (exp & 1) == 1 { - acc = acc * base; - // since exp!=0, finally the exp must be 1. - if exp == 1 { - return acc; + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + acc * base + } else { + // This is faster than the above when the exponent is not known + // at compile time. We can't use the same code for the constant + // exponent case because LLVM is currently unable to unroll + // this loop. + loop { + if (exp & 1) == 1 { + acc = acc * base; + // since exp!=0, finally the exp must be 1. + if exp == 1 { + return acc; + } } + exp /= 2; + base = base * base; } - exp /= 2; - base = base * base; } } diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 24352593fca3d..5b3ef78d39a3d 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -2050,54 +2050,41 @@ macro_rules! uint_impl { #[inline] #[rustc_allow_const_fn_unstable(is_val_statically_known)] pub const fn wrapping_pow(self, mut exp: u32) -> Self { + if exp == 0 { + return 1; + } let mut base = self; + let mut acc: Self = 1; if intrinsics::is_val_statically_known(exp) { - // Unroll multiplications for small exponent values. - // This gives the optimizer a way to efficiently inline call sites - // for the most common use cases with constant exponents. - // Currently, LLVM is unable to unroll the loop below. - match exp { - 0 => return 1, - 1 => return base, - 2 => return base.wrapping_mul(base), - 3 => { - let squared = base.wrapping_mul(base); - return squared.wrapping_mul(base); - } - 4 => { - let squared = base.wrapping_mul(base); - return squared.wrapping_mul(squared); + while exp > 1 { + if (exp & 1) == 1 { + acc = acc.wrapping_mul(base); } - 5 => { - let squared = base.wrapping_mul(base); - return squared.wrapping_mul(squared).wrapping_mul(base); - } - 6 => { - let cubed = base.wrapping_mul(base).wrapping_mul(base); - return cubed.wrapping_mul(cubed); - } - _ => {} + exp /= 2; + base = base.wrapping_mul(base); } - } else { - if exp == 0 { - return 1; - } - } - debug_assert!(exp != 0); - let mut acc: Self = 1; - - loop { - if (exp & 1) == 1 { - acc = acc.wrapping_mul(base); - // since exp!=0, finally the exp must be 1. - if exp == 1 { - return acc; + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary. + acc.wrapping_mul(base) + } else { + // This is faster than the above when the exponent is not known + // at compile time. We can't use the same code for the constant + // exponent case because LLVM is currently unable to unroll + // this loop. + loop { + if (exp & 1) == 1 { + acc = acc.wrapping_mul(base); + // since exp!=0, finally the exp must be 1. + if exp == 1 { + return acc; + } } + exp /= 2; + base = base.wrapping_mul(base); } - exp /= 2; - base = base.wrapping_mul(base); } } @@ -2578,54 +2565,42 @@ macro_rules! uint_impl { #[rustc_inherit_overflow_checks] #[rustc_allow_const_fn_unstable(is_val_statically_known)] pub const fn pow(self, mut exp: u32) -> Self { + if exp == 0 { + return 1; + } let mut base = self; + let mut acc = 1; if intrinsics::is_val_statically_known(exp) { - // Unroll multiplications for small exponent values. - // This gives the optimizer a way to efficiently inline call sites - // for the most common use cases with constant exponents. - // Currently, LLVM is unable to unroll the loop below. - match exp { - 0 => return 1, - 1 => return base, - 2 => return base * base, - 3 => { - let squared = base * base; - return squared * base; - } - 4 => { - let squared = base * base; - return squared * squared; + while exp > 1 { + if (exp & 1) == 1 { + acc = acc * base; } - 5 => { - let squared = base * base; - return squared * squared * base; - } - 6 => { - let cubed = base * base * base; - return cubed * cubed; - } - _ => {} + exp /= 2; + base = base * base; } - } else { - if exp == 0 { - return 1; - } - } - debug_assert!(exp != 0); - let mut acc = 1; - - loop { - if (exp & 1) == 1 { - acc = acc * base; - // since exp!=0, finally the exp must be 1. - if exp == 1 { - return acc; + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + acc * base + } else { + // This is faster than the above when the exponent is not known + // at compile time. We can't use the same code for the constant + // exponent case because LLVM is currently unable to unroll + // this loop. + loop { + if (exp & 1) == 1 { + acc = acc * base; + // since exp!=0, finally the exp must be 1. + if exp == 1 { + return acc; + } } + exp /= 2; + base = base * base; } - exp /= 2; - base = base * base; } } From 399ef23d2bf2b1619d360a87de9b83edf9d99762 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Wed, 17 Jul 2024 13:45:31 +0200 Subject: [PATCH 06/14] Allow to customize `// TODO:` comment for deprecated safe autofix Relevant for the deprecation of `CommandExt::before_exit` in #125970. --- compiler/rustc_feature/src/builtin_attrs.rs | 4 ++-- compiler/rustc_mir_build/messages.ftl | 2 +- .../rustc_mir_build/src/check_unsafety.rs | 22 +++++++++++++++++-- compiler/rustc_mir_build/src/errors.rs | 6 ++--- compiler/rustc_span/src/symbol.rs | 1 + library/std/src/env.rs | 16 ++++++++++++-- .../ui/rust-2024/unsafe-env-suggestion.stderr | 4 ++-- 7 files changed, 42 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 72ea55d5999a2..1b4c18e96fc74 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -643,8 +643,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ through unstable paths" ), rustc_attr!( - rustc_deprecated_safe_2024, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::Yes, + rustc_deprecated_safe_2024, Normal, template!(List: r#"todo = "...""#), + ErrorFollowing, EncodeCrossCrate::Yes, "rustc_deprecated_safe_2024 is supposed to be used in libstd only", ), diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index dda4debecec67..91c4de7963665 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -30,7 +30,7 @@ mir_build_call_to_deprecated_safe_fn_requires_unsafe = call to deprecated safe function `{$function}` is unsafe and requires unsafe block .note = consult the function's documentation for information on how to avoid undefined behavior .label = call to unsafe function - .suggestion = you can wrap the call in an `unsafe` block if you can guarantee the code is only ever called from single-threaded code + .suggestion = you can wrap the call in an `unsafe` block if you can guarantee its unsafe preconditions mir_build_call_to_fn_with_requires_unsafe = call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 54a4204da71e8..f856555a95c21 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -96,9 +96,27 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { // from an edition before 2024. &UnsafeOpKind::CallToUnsafeFunction(Some(id)) if !span.at_least_rust_2024() - && self.tcx.has_attr(id, sym::rustc_deprecated_safe_2024) => + && let Some(attr) = self.tcx.get_attr(id, sym::rustc_deprecated_safe_2024) => { + let suggestion = attr + .meta_item_list() + .unwrap_or_default() + .into_iter() + .find(|item| item.has_name(sym::todo)) + .map(|item| { + item.value_str().expect( + "`#[rustc_deprecated_safe_2024(todo)]` must have a string value", + ) + }); + let sm = self.tcx.sess.source_map(); + let suggestion = suggestion + .and_then(|suggestion| { + sm.indentation_before(span) + .map(|indent| format!("{}// TODO: {}\n", indent, suggestion)) // ignore-tidy-todo + }) + .unwrap_or_default(); + self.tcx.emit_node_span_lint( DEPRECATED_SAFE_2024, self.hir_context, @@ -107,7 +125,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { span, function: with_no_trimmed_paths!(self.tcx.def_path_str(id)), sub: CallToDeprecatedSafeFnRequiresUnsafeSub { - indent: sm.indentation_before(span).unwrap_or_default(), + start_of_line_suggestion: suggestion, start_of_line: sm.span_extend_to_line(span).shrink_to_lo(), left: span.shrink_to_lo(), right: span.shrink_to_hi(), diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 42eca71ca3f30..8c45f949e4350 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -35,10 +35,8 @@ pub(crate) struct CallToDeprecatedSafeFnRequiresUnsafe { #[derive(Subdiagnostic)] #[multipart_suggestion(mir_build_suggestion, applicability = "machine-applicable")] pub(crate) struct CallToDeprecatedSafeFnRequiresUnsafeSub { - pub(crate) indent: String, - #[suggestion_part( - code = "{indent}// TODO: Audit that the environment access only happens in single-threaded code.\n" // ignore-tidy-todo - )] + pub(crate) start_of_line_suggestion: String, + #[suggestion_part(code = "{start_of_line_suggestion}")] pub(crate) start_of_line: Span, #[suggestion_part(code = "unsafe {{ ")] pub(crate) left: Span, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 9cb729ec48588..95810a9a8379a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1897,6 +1897,7 @@ symbols! { to_string, to_string_method, to_vec, + todo, todo_macro, tool_attributes, tool_lints, diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 50ae83090c7e1..631d86dbe6e00 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -355,7 +355,13 @@ impl Error for VarError { /// } /// assert_eq!(env::var(key), Ok("VALUE".to_string())); /// ``` -#[rustc_deprecated_safe_2024] +#[cfg_attr(bootstrap, rustc_deprecated_safe_2024)] +#[cfg_attr( + not(bootstrap), + rustc_deprecated_safe_2024( + todo = "Audit that the environment access only happens in single-threaded code." + ) +)] #[stable(feature = "env", since = "1.0.0")] pub unsafe fn set_var, V: AsRef>(key: K, value: V) { let (key, value) = (key.as_ref(), value.as_ref()); @@ -419,7 +425,13 @@ pub unsafe fn set_var, V: AsRef>(key: K, value: V) { /// } /// assert!(env::var(key).is_err()); /// ``` -#[rustc_deprecated_safe_2024] +#[cfg_attr(bootstrap, rustc_deprecated_safe_2024)] +#[cfg_attr( + not(bootstrap), + rustc_deprecated_safe_2024( + todo = "Audit that the environment access only happens in single-threaded code." + ) +)] #[stable(feature = "env", since = "1.0.0")] pub unsafe fn remove_var>(key: K) { let key = key.as_ref(); diff --git a/tests/ui/rust-2024/unsafe-env-suggestion.stderr b/tests/ui/rust-2024/unsafe-env-suggestion.stderr index 3aa10a3bed682..5c90c08e2ddfb 100644 --- a/tests/ui/rust-2024/unsafe-env-suggestion.stderr +++ b/tests/ui/rust-2024/unsafe-env-suggestion.stderr @@ -11,7 +11,7 @@ note: the lint level is defined here | LL | #![deny(deprecated_safe_2024)] | ^^^^^^^^^^^^^^^^^^^^ -help: you can wrap the call in an `unsafe` block if you can guarantee the code is only ever called from single-threaded code +help: you can wrap the call in an `unsafe` block if you can guarantee its unsafe preconditions | LL + // TODO: Audit that the environment access only happens in single-threaded code. LL ~ unsafe { env::set_var("FOO", "BAR") }; @@ -25,7 +25,7 @@ LL | env::remove_var("FOO"); | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! = note: for more information, see issue #27970 -help: you can wrap the call in an `unsafe` block if you can guarantee the code is only ever called from single-threaded code +help: you can wrap the call in an `unsafe` block if you can guarantee its unsafe preconditions | LL + // TODO: Audit that the environment access only happens in single-threaded code. LL ~ unsafe { env::remove_var("FOO") }; From 811d7dd11302e86d1678f7d61586d51e54c47e27 Mon Sep 17 00:00:00 2001 From: Tobias Bucher Date: Mon, 29 Jul 2024 13:31:59 +0200 Subject: [PATCH 07/14] `#[deprecated_safe_2024]`: Also use the `// TODO:` hint in the compiler error This doesn't work for translated compiler error messages. --- compiler/rustc_feature/src/builtin_attrs.rs | 2 +- compiler/rustc_mir_build/messages.ftl | 2 +- compiler/rustc_mir_build/src/check_unsafety.rs | 14 ++++++++++---- compiler/rustc_mir_build/src/errors.rs | 1 + compiler/rustc_span/src/symbol.rs | 2 +- library/std/src/env.rs | 4 ++-- tests/ui/rust-2024/unsafe-env-suggestion.stderr | 4 ++-- 7 files changed, 18 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 1b4c18e96fc74..d593f05c8c6db 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -643,7 +643,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ through unstable paths" ), rustc_attr!( - rustc_deprecated_safe_2024, Normal, template!(List: r#"todo = "...""#), + rustc_deprecated_safe_2024, Normal, template!(List: r#"audit_that = "...""#), ErrorFollowing, EncodeCrossCrate::Yes, "rustc_deprecated_safe_2024 is supposed to be used in libstd only", ), diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 91c4de7963665..7baf0256dd890 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -30,7 +30,7 @@ mir_build_call_to_deprecated_safe_fn_requires_unsafe = call to deprecated safe function `{$function}` is unsafe and requires unsafe block .note = consult the function's documentation for information on how to avoid undefined behavior .label = call to unsafe function - .suggestion = you can wrap the call in an `unsafe` block if you can guarantee its unsafe preconditions + .suggestion = you can wrap the call in an `unsafe` block if you can guarantee {$guarantee} mir_build_call_to_fn_with_requires_unsafe = call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index f856555a95c21..9b85ad0ad0891 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -102,18 +102,23 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { .meta_item_list() .unwrap_or_default() .into_iter() - .find(|item| item.has_name(sym::todo)) + .find(|item| item.has_name(sym::audit_that)) .map(|item| { item.value_str().expect( - "`#[rustc_deprecated_safe_2024(todo)]` must have a string value", + "`#[rustc_deprecated_safe_2024(audit_that)]` must have a string value", ) }); let sm = self.tcx.sess.source_map(); + let guarantee = suggestion + .as_ref() + .map(|suggestion| format!("that {}", suggestion)) + .unwrap_or_else(|| String::from("its unsafe preconditions")); let suggestion = suggestion .and_then(|suggestion| { - sm.indentation_before(span) - .map(|indent| format!("{}// TODO: {}\n", indent, suggestion)) // ignore-tidy-todo + sm.indentation_before(span).map(|indent| { + format!("{}// TODO: Audit that {}.\n", indent, suggestion) // ignore-tidy-todo + }) }) .unwrap_or_default(); @@ -124,6 +129,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { CallToDeprecatedSafeFnRequiresUnsafe { span, function: with_no_trimmed_paths!(self.tcx.def_path_str(id)), + guarantee, sub: CallToDeprecatedSafeFnRequiresUnsafeSub { start_of_line_suggestion: suggestion, start_of_line: sm.span_extend_to_line(span).shrink_to_lo(), diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 8c45f949e4350..34577f102d1c5 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -28,6 +28,7 @@ pub(crate) struct CallToDeprecatedSafeFnRequiresUnsafe { #[label] pub(crate) span: Span, pub(crate) function: String, + pub(crate) guarantee: String, #[subdiagnostic] pub(crate) sub: CallToDeprecatedSafeFnRequiresUnsafeSub, } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 95810a9a8379a..a2e94492f8c23 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -472,6 +472,7 @@ symbols! { attr, attr_literals, attributes, + audit_that, augmented_assignments, auto_traits, automatically_derived, @@ -1897,7 +1898,6 @@ symbols! { to_string, to_string_method, to_vec, - todo, todo_macro, tool_attributes, tool_lints, diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 631d86dbe6e00..80890e61471c6 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -359,7 +359,7 @@ impl Error for VarError { #[cfg_attr( not(bootstrap), rustc_deprecated_safe_2024( - todo = "Audit that the environment access only happens in single-threaded code." + audit_that = "the environment access only happens in single-threaded code" ) )] #[stable(feature = "env", since = "1.0.0")] @@ -429,7 +429,7 @@ pub unsafe fn set_var, V: AsRef>(key: K, value: V) { #[cfg_attr( not(bootstrap), rustc_deprecated_safe_2024( - todo = "Audit that the environment access only happens in single-threaded code." + audit_that = "the environment access only happens in single-threaded code" ) )] #[stable(feature = "env", since = "1.0.0")] diff --git a/tests/ui/rust-2024/unsafe-env-suggestion.stderr b/tests/ui/rust-2024/unsafe-env-suggestion.stderr index 5c90c08e2ddfb..1506741f6bc9b 100644 --- a/tests/ui/rust-2024/unsafe-env-suggestion.stderr +++ b/tests/ui/rust-2024/unsafe-env-suggestion.stderr @@ -11,7 +11,7 @@ note: the lint level is defined here | LL | #![deny(deprecated_safe_2024)] | ^^^^^^^^^^^^^^^^^^^^ -help: you can wrap the call in an `unsafe` block if you can guarantee its unsafe preconditions +help: you can wrap the call in an `unsafe` block if you can guarantee that the environment access only happens in single-threaded code | LL + // TODO: Audit that the environment access only happens in single-threaded code. LL ~ unsafe { env::set_var("FOO", "BAR") }; @@ -25,7 +25,7 @@ LL | env::remove_var("FOO"); | = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! = note: for more information, see issue #27970 -help: you can wrap the call in an `unsafe` block if you can guarantee its unsafe preconditions +help: you can wrap the call in an `unsafe` block if you can guarantee that the environment access only happens in single-threaded code | LL + // TODO: Audit that the environment access only happens in single-threaded code. LL ~ unsafe { env::remove_var("FOO") }; From 2a000c8d7073ad1b857c8028a5bbaa21eb12ced5 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 13 Aug 2024 20:23:48 +1000 Subject: [PATCH 08/14] Don't panic on unknown JSON-like output lines This function is called for both compiler and non-compiler output, so if the line isn't recognized as JSON from the compiler then just print it as-is. --- src/tools/compiletest/src/json.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 76b83f02b149a..70c05925b50fc 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -127,11 +127,10 @@ pub fn extract_rendered(output: &str) -> String { // Ignore the notification. None } else { - print!( - "failed to decode compiler output as json: line: {}\noutput: {}", - line, output - ); - panic!() + // This function is called for both compiler and non-compiler output, + // so if the line isn't recognized as JSON from the compiler then + // just print it as-is. + Some(format!("{line}\n")) } } else { // preserve non-JSON lines, such as ICEs From 355f264d32cf449e00adeeaccfb17a1e2f3fdd18 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 13 Aug 2024 20:24:53 +1000 Subject: [PATCH 09/14] Remove a confusing comment The JSON messages parsed by this file are from the _compiler_, not from libtest. --- src/tools/compiletest/src/json.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 70c05925b50fc..0da93dcafa20b 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -1,5 +1,4 @@ //! These structs are a subset of the ones found in `rustc_errors::json`. -//! They are only used for deserialization of JSON output provided by libtest. use std::path::{Path, PathBuf}; use std::str::FromStr; From 53e87d211ca314c5e3e664ef254bd20d134c9a00 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 13 Aug 2024 15:03:18 +0200 Subject: [PATCH 10/14] Remove duplicated rustdoc ui test --- .../generate-link-to-definition-opt2.rs | 6 ------ .../generate-link-to-definition-opt2.stderr | 2 -- 2 files changed, 8 deletions(-) delete mode 100644 tests/rustdoc-ui/generate-link-to-definition/generate-link-to-definition-opt2.rs delete mode 100644 tests/rustdoc-ui/generate-link-to-definition/generate-link-to-definition-opt2.stderr diff --git a/tests/rustdoc-ui/generate-link-to-definition/generate-link-to-definition-opt2.rs b/tests/rustdoc-ui/generate-link-to-definition/generate-link-to-definition-opt2.rs deleted file mode 100644 index 718522059799e..0000000000000 --- a/tests/rustdoc-ui/generate-link-to-definition/generate-link-to-definition-opt2.rs +++ /dev/null @@ -1,6 +0,0 @@ -// This test purpose is to check that the "--generate-link-to-definition" -// option can only be used with HTML generation. - -//@ compile-flags: -Zunstable-options --generate-link-to-definition --show-coverage - -pub fn f() {} diff --git a/tests/rustdoc-ui/generate-link-to-definition/generate-link-to-definition-opt2.stderr b/tests/rustdoc-ui/generate-link-to-definition/generate-link-to-definition-opt2.stderr deleted file mode 100644 index 4c8c607e7da23..0000000000000 --- a/tests/rustdoc-ui/generate-link-to-definition/generate-link-to-definition-opt2.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: --generate-link-to-definition option can only be used with HTML output format - From d2177d90b04e7af7d52279fe4664002f1e2a9c58 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 13 Aug 2024 15:07:26 +0200 Subject: [PATCH 11/14] Emit a warning instead of an error if `--generate-link-to-definition` is used with other output formats than HTML --- src/librustdoc/config.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 9c7a9f8467f5a..d599fead2668a 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -733,9 +733,11 @@ impl Options { let html_no_source = matches.opt_present("html-no-source"); if generate_link_to_definition && (show_coverage || output_format != OutputFormat::Html) { - dcx.fatal( - "--generate-link-to-definition option can only be used with HTML output format", - ); + dcx.struct_warn( + "`--generate-link-to-definition` option can only be used with HTML output format", + ) + .with_note("`--generate-link-to-definition` option will be ignored") + .emit(); } let scrape_examples_options = ScrapeExamplesOptions::new(matches, dcx); From afbab80681de5f5eb205d1ace743225baf27a9f0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 13 Aug 2024 15:08:07 +0200 Subject: [PATCH 12/14] Update rustdoc-ui test for `--generate-link-to-definition` option --- .../generate-link-to-definition-opt.rs | 1 + .../generate-link-to-definition-opt.stderr | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/rustdoc-ui/generate-link-to-definition/generate-link-to-definition-opt.rs b/tests/rustdoc-ui/generate-link-to-definition/generate-link-to-definition-opt.rs index f11b94bb036c6..babdbd0a69216 100644 --- a/tests/rustdoc-ui/generate-link-to-definition/generate-link-to-definition-opt.rs +++ b/tests/rustdoc-ui/generate-link-to-definition/generate-link-to-definition-opt.rs @@ -2,5 +2,6 @@ // option can only be used with HTML generation. //@ compile-flags: -Zunstable-options --generate-link-to-definition --output-format json +//@ check-pass pub fn f() {} diff --git a/tests/rustdoc-ui/generate-link-to-definition/generate-link-to-definition-opt.stderr b/tests/rustdoc-ui/generate-link-to-definition/generate-link-to-definition-opt.stderr index 4c8c607e7da23..62b0e3ce408b7 100644 --- a/tests/rustdoc-ui/generate-link-to-definition/generate-link-to-definition-opt.stderr +++ b/tests/rustdoc-ui/generate-link-to-definition/generate-link-to-definition-opt.stderr @@ -1,2 +1,4 @@ -error: --generate-link-to-definition option can only be used with HTML output format +warning: `--generate-link-to-definition` option can only be used with HTML output format + | + = note: `--generate-link-to-definition` option will be ignored From 87a4c325d2767e5e0baf0c2a4d0cc12bb78ca356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 13 Aug 2024 18:08:30 +0200 Subject: [PATCH 13/14] Fix target triple in bootstrap --- src/bootstrap/src/core/download.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 8131666fcb225..fd85650bc5620 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -519,7 +519,7 @@ impl Config { extra_components: &[&str], download_component: fn(&Config, String, &str, &str), ) { - let host = self.build; + let host = self.build.triple; let bin_root = self.out.join(host).join(sysroot); let rustc_stamp = bin_root.join(".rustc-stamp"); From 5082e25263064e93aa03ba7374ebbbdf5454eac5 Mon Sep 17 00:00:00 2001 From: Michael Woerister Date: Tue, 13 Aug 2024 20:16:14 +0200 Subject: [PATCH 14/14] Add mw back to review rotation --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index 33108f743cb94..a98d5f6a7c215 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -913,7 +913,7 @@ cc = ["@kobzol"] [assign] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" -users_on_vacation = ["jyn514", "jhpratt", "oli-obk", "michaelwoerister"] +users_on_vacation = ["jyn514", "jhpratt", "oli-obk"] [assign.adhoc_groups] compiler-team = [