From f25126e9c9b25eb46462fd82f83028956e8d6ea0 Mon Sep 17 00:00:00 2001 From: usamoi Date: Wed, 3 Jan 2024 20:24:24 +0800 Subject: [PATCH 01/28] add avx512fp16 to x86 target features --- compiler/rustc_codegen_gcc/src/lib.rs | 2 +- compiler/rustc_target/src/target_features.rs | 1 + tests/ui/check-cfg/well-known-values.stderr | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 03f8f43ff1643..f8f054db65ede 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -408,7 +408,7 @@ pub fn target_features(sess: &Session, allow_unstable: bool, target_info: &Locke .filter(|_feature| { target_info.cpu_supports(_feature) /* - adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512ifma, + adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma, avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq, bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm, sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 5f5de57dd1d87..c350a37975d23 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -201,6 +201,7 @@ const X86_ALLOWED_FEATURES: &[(&str, Stability)] = &[ ("avx512dq", Unstable(sym::avx512_target_feature)), ("avx512er", Unstable(sym::avx512_target_feature)), ("avx512f", Unstable(sym::avx512_target_feature)), + ("avx512fp16", Unstable(sym::avx512_target_feature)), ("avx512ifma", Unstable(sym::avx512_target_feature)), ("avx512pf", Unstable(sym::avx512_target_feature)), ("avx512vbmi", Unstable(sym::avx512_target_feature)), diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 9d134dcfcfd88..0ce0827c15a89 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -143,7 +143,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_feature = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512er`, `avx512f`, `avx512ifma`, `avx512pf`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `f`, `f16c`, `f32mm`, `f64mm`, `fast-unaligned-access`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, `zkt` + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512er`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512pf`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `f`, `f16c`, `f32mm`, `f64mm`, `fast-unaligned-access`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, `zkt` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` From 3434466a7f3d82103beb32e1b53ec26231cbe6c7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 15 Jan 2024 16:20:37 +1100 Subject: [PATCH 02/28] Tweak `emit_stashed_diagnostics`. `take` + `into_iter` + pattern matching is nicer than `drain` + `map` + `collect`. --- compiler/rustc_errors/src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 960b68196ff02..901fe3fb79930 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1224,9 +1224,8 @@ impl DiagCtxtInner { /// Emit all stashed diagnostics. fn emit_stashed_diagnostics(&mut self) -> Option { let has_errors = self.has_errors(); - let diags = self.stashed_diagnostics.drain(..).map(|x| x.1).collect::>(); let mut reported = None; - for diag in diags { + for (_, diag) in std::mem::take(&mut self.stashed_diagnostics).into_iter() { // Decrement the count tracking the stash; emitting will increment it. if diag.is_error() { if diag.is_lint.is_some() { From 3db37fb78a9a6b76373faf85c2976a2916599f85 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 30 Jan 2024 14:09:24 +1100 Subject: [PATCH 03/28] A small fix in `enforce_slug_naming.rs`. In #119972 the code should have become `E0123` rather than `0123`. This fix doesn't affect the outcome because the proc macro errors out before the type of the code is checked, but the fix makes the test's code consistent with other similar code elsewhere. --- tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.rs | 2 +- tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.rs b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.rs index 785da11b9b2e3..3056ebb7575fd 100644 --- a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.rs +++ b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.rs @@ -19,6 +19,6 @@ use rustc_errors::{Applicability, MultiSpan}; extern crate rustc_session; #[derive(Diagnostic)] -#[diag(compiletest_example, code = 0123)] +#[diag(compiletest_example, code = E0123)] //~^ ERROR diagnostic slug and crate name do not match struct Hello {} diff --git a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr index eda24a555f848..df1bad3cad0cf 100644 --- a/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr +++ b/tests/ui-fulldeps/session-diagnostic/enforce_slug_naming.stderr @@ -1,7 +1,7 @@ error: diagnostic slug and crate name do not match --> $DIR/enforce_slug_naming.rs:22:8 | -LL | #[diag(compiletest_example, code = 0123)] +LL | #[diag(compiletest_example, code = E0123)] | ^^^^^^^^^^^^^^^^^^^ | = note: slug is `compiletest_example` but the crate name is `rustc_dummy` From 26eb6da4e7f19fd1408eac2c67891f3dbfc47e5a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 30 Jan 2024 14:46:51 +1100 Subject: [PATCH 04/28] Fit more values into `DiagnosticArgValue::Number`. It contains an `i128`, but when creating them we convert any number outside the range -100..100 to a string, because Fluent uses an `f64`. It's all a bit strange. This commit changes the `i128` to an `i32`, which fits safely in Fluent's `f64`, and removes the -100..100 range check. This means that only integers outside the range of `i32` will be converted to strings. --- compiler/rustc_errors/src/diagnostic.rs | 5 ++++- compiler/rustc_errors/src/diagnostic_impls.rs | 8 ++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index b87eef07fd53a..249155ba7c641 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -33,7 +33,10 @@ pub type DiagnosticArgName = Cow<'static, str>; #[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] pub enum DiagnosticArgValue { Str(Cow<'static, str>), - Number(i128), + // This gets converted to a `FluentNumber`, which is an `f64`. An `i32` + // safely fits in an `f64`. Any integers bigger than that will be converted + // to strings in `into_diagnostic_arg` and stored using the `Str` variant. + Number(i32), StrListSepByAnd(Vec>), } diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index faab3fc663a82..15effd3cbec9b 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -63,12 +63,8 @@ macro_rules! into_diagnostic_arg_for_number { $( impl IntoDiagnosticArg for $ty { fn into_diagnostic_arg(self) -> DiagnosticArgValue { - // HACK: `FluentNumber` the underline backing struct represent - // numbers using a f64 which can't represent all the i128 numbers - // So in order to be able to use fluent selectors and still - // have all the numbers representable we only convert numbers - // below a certain threshold. - if let Ok(n) = TryInto::::try_into(self) && n >= -100 && n <= 100 { + // Convert to a string if it won't fit into `Number`. + if let Ok(n) = TryInto::::try_into(self) { DiagnosticArgValue::Number(n) } else { self.to_string().into_diagnostic_arg() From 2621f7fd9ba97bbbd1b5b1df96184353948e2249 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 30 Jan 2024 17:10:48 +1100 Subject: [PATCH 05/28] Rework `StringPart`. When there are two possibilities, both of which use a `String`, it's nicer to use a struct than an enum. Especially when mapping the contents into a tuple. --- compiler/rustc_errors/src/diagnostic.rs | 36 +++++++++++-------------- compiler/rustc_errors/src/snippet.rs | 2 +- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 249155ba7c641..6deaaef780d41 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -165,10 +165,10 @@ impl DiagnosticStyledString { DiagnosticStyledString(vec![]) } pub fn push_normal>(&mut self, t: S) { - self.0.push(StringPart::Normal(t.into())); + self.0.push(StringPart::normal(t.into())); } pub fn push_highlighted>(&mut self, t: S) { - self.0.push(StringPart::Highlighted(t.into())); + self.0.push(StringPart::highlighted(t.into())); } pub fn push>(&mut self, t: S, highlight: bool) { if highlight { @@ -178,29 +178,31 @@ impl DiagnosticStyledString { } } pub fn normal>(t: S) -> DiagnosticStyledString { - DiagnosticStyledString(vec![StringPart::Normal(t.into())]) + DiagnosticStyledString(vec![StringPart::normal(t.into())]) } pub fn highlighted>(t: S) -> DiagnosticStyledString { - DiagnosticStyledString(vec![StringPart::Highlighted(t.into())]) + DiagnosticStyledString(vec![StringPart::highlighted(t.into())]) } pub fn content(&self) -> String { - self.0.iter().map(|x| x.content()).collect::() + self.0.iter().map(|x| x.content.as_str()).collect::() } } #[derive(Debug, PartialEq, Eq)] -pub enum StringPart { - Normal(String), - Highlighted(String), +pub struct StringPart { + content: String, + style: Style, } impl StringPart { - pub fn content(&self) -> &str { - match self { - &StringPart::Normal(ref s) | &StringPart::Highlighted(ref s) => s, - } + fn normal(content: String) -> StringPart { + StringPart { content, style: Style::NoStyle } + } + + fn highlighted(content: String) -> StringPart { + StringPart { content, style: Style::Highlight } } } @@ -394,16 +396,10 @@ impl Diagnostic { }; let mut msg: Vec<_> = vec![(format!("{}{} `", " ".repeat(expected_padding), expected_label), Style::NoStyle)]; - msg.extend(expected.0.iter().map(|x| match *x { - StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), - StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), - })); + msg.extend(expected.0.into_iter().map(|p| (p.content, p.style))); msg.push((format!("`{expected_extra}\n"), Style::NoStyle)); msg.push((format!("{}{} `", " ".repeat(found_padding), found_label), Style::NoStyle)); - msg.extend(found.0.iter().map(|x| match *x { - StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), - StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), - })); + msg.extend(found.0.into_iter().map(|p| (p.content, p.style))); msg.push((format!("`{found_extra}"), Style::NoStyle)); // For now, just attach these as notes. diff --git a/compiler/rustc_errors/src/snippet.rs b/compiler/rustc_errors/src/snippet.rs index 98eb70b5fceee..b55f78538852a 100644 --- a/compiler/rustc_errors/src/snippet.rs +++ b/compiler/rustc_errors/src/snippet.rs @@ -197,7 +197,7 @@ pub struct StyledString { pub style: Style, } -#[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] pub enum Style { MainHeaderMsg, HeaderMsg, From 6ac035df442a27cf9e99ab4ec25bb6147a700902 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 1 Feb 2024 22:53:25 +0000 Subject: [PATCH 06/28] Revert unsound libcore changes of #119911 --- library/core/src/lib.rs | 1 - library/core/src/num/int_macros.rs | 284 ++++++++-------------------- library/core/src/num/uint_macros.rs | 249 ++++++++---------------- tests/codegen/pow_of_two.rs | 55 ------ 4 files changed, 149 insertions(+), 440 deletions(-) delete mode 100644 tests/codegen/pow_of_two.rs diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 2af242d4b5071..ead8cbe0e2f43 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -200,7 +200,6 @@ // // Language features: // tidy-alphabetical-start -#![cfg_attr(not(bootstrap), feature(is_val_statically_known))] #![feature(abi_unadjusted)] #![feature(adt_const_params)] #![feature(allow_internal_unsafe)] diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index bb35b6128ea5a..d052dcc3e6ee6 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1374,59 +1374,26 @@ macro_rules! int_impl { #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)] #[inline] pub const fn checked_pow(self, mut exp: u32) -> Option { - // SAFETY: This path has the same behavior as the other. - if unsafe { intrinsics::is_val_statically_known(self) } - && self.unsigned_abs().is_power_of_two() - { - if self == 1 { // Avoid divide by zero - return Some(1); - } - if self == -1 { // Avoid divide by zero - return Some(if exp & 1 != 0 { -1 } else { 1 }); - } - // SAFETY: We just checked this is a power of two. and above zero. - let power_used = unsafe { intrinsics::cttz_nonzero(self.wrapping_abs()) as u32 }; - if exp > Self::BITS / power_used { return None; } // Division of constants is free - - // SAFETY: exp <= Self::BITS / power_used - let res = unsafe { intrinsics::unchecked_shl( - 1 as Self, - intrinsics::unchecked_mul(power_used, exp) as Self - )}; - // LLVM doesn't always optimize out the checks - // at the ir level. - - let sign = self.is_negative() && exp & 1 != 0; - if !sign && res == Self::MIN { - None - } else if sign { - Some(res.wrapping_neg()) - } else { - Some(res) - } - } else { - if exp == 0 { - return Some(1); - } - let mut base = self; - let mut acc: Self = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = try_opt!(acc.checked_mul(base)); - } - exp /= 2; - base = try_opt!(base.checked_mul(base)); + if exp == 0 { + return Some(1); + } + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = try_opt!(acc.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) + 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 @@ -2091,58 +2058,27 @@ macro_rules! int_impl { #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)] #[inline] pub const fn wrapping_pow(self, mut exp: u32) -> Self { - // SAFETY: This path has the same behavior as the other. - if unsafe { intrinsics::is_val_statically_known(self) } - && self.unsigned_abs().is_power_of_two() - { - if self == 1 { // Avoid divide by zero - return 1; - } - if self == -1 { // Avoid divide by zero - return if exp & 1 != 0 { -1 } else { 1 }; - } - // SAFETY: We just checked this is a power of two. and above zero. - let power_used = unsafe { intrinsics::cttz_nonzero(self.wrapping_abs()) as u32 }; - if exp > Self::BITS / power_used { return 0; } // Division of constants is free - - // SAFETY: exp <= Self::BITS / power_used - let res = unsafe { intrinsics::unchecked_shl( - 1 as Self, - intrinsics::unchecked_mul(power_used, exp) as Self - )}; - // LLVM doesn't always optimize out the checks - // at the ir level. - - let sign = self.is_negative() && exp & 1 != 0; - if sign { - res.wrapping_neg() - } else { - res - } - } else { - if exp == 0 { - return 1; - } - let mut base = self; - let mut acc: Self = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = acc.wrapping_mul(base); - } - exp /= 2; - base = base.wrapping_mul(base); - } + if exp == 0 { + return 1; + } + let mut base = self; + let mut acc: Self = 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. - acc.wrapping_mul(base) + while exp > 1 { + if (exp & 1) == 1 { + acc = acc.wrapping_mul(base); + } + 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` @@ -2625,68 +2561,36 @@ macro_rules! int_impl { #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)] #[inline] pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { - // SAFETY: This path has the same behavior as the other. - if unsafe { intrinsics::is_val_statically_known(self) } - && self.unsigned_abs().is_power_of_two() - { - if self == 1 { // Avoid divide by zero - return (1, false); - } - if self == -1 { // Avoid divide by zero - return (if exp & 1 != 0 { -1 } else { 1 }, false); - } - // SAFETY: We just checked this is a power of two. and above zero. - let power_used = unsafe { intrinsics::cttz_nonzero(self.wrapping_abs()) as u32 }; - if exp > Self::BITS / power_used { return (0, true); } // Division of constants is free - - // SAFETY: exp <= Self::BITS / power_used - let res = unsafe { intrinsics::unchecked_shl( - 1 as Self, - intrinsics::unchecked_mul(power_used, exp) as Self - )}; - // LLVM doesn't always optimize out the checks - // at the ir level. - - let sign = self.is_negative() && exp & 1 != 0; - let overflow = res == Self::MIN; - if sign { - (res.wrapping_neg(), overflow) - } else { - (res, overflow) - } - } else { - if exp == 0 { - return (1,false); - } - let mut base = self; - let mut acc: Self = 1; - let mut overflown = false; - // Scratch space for storing results of overflowing_mul. - let mut r; - - while exp > 1 { - if (exp & 1) == 1 { - r = acc.overflowing_mul(base); - acc = r.0; - overflown |= r.1; - } - exp /= 2; - r = base.overflowing_mul(base); - base = r.0; + if exp == 0 { + return (1,false); + } + let mut base = self; + let mut acc: Self = 1; + let mut overflown = false; + // Scratch space for storing results of overflowing_mul. + let mut r; + + while exp > 1 { + if (exp & 1) == 1 { + r = acc.overflowing_mul(base); + acc = 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 + exp /= 2; + r = base.overflowing_mul(base); + 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. @@ -2704,68 +2608,28 @@ macro_rules! int_impl { #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)] #[inline] #[rustc_inherit_overflow_checks] - #[track_caller] // Hides the hackish overflow check for powers of two. pub const fn pow(self, mut exp: u32) -> Self { - // SAFETY: This path has the same behavior as the other. - if unsafe { intrinsics::is_val_statically_known(self) } - && self.unsigned_abs().is_power_of_two() - { - if self == 1 { // Avoid divide by zero - return 1; - } - if self == -1 { // Avoid divide by zero - return if exp & 1 != 0 { -1 } else { 1 }; - } - // SAFETY: We just checked this is a power of two. and above zero. - let power_used = unsafe { intrinsics::cttz_nonzero(self.wrapping_abs()) as u32 }; - if exp > Self::BITS / power_used { // Division of constants is free - #[allow(arithmetic_overflow)] - return Self::MAX * Self::MAX * 0; - } + if exp == 0 { + return 1; + } + let mut base = self; + let mut acc = 1; - // SAFETY: exp <= Self::BITS / power_used - let res = unsafe { intrinsics::unchecked_shl( - 1 as Self, - intrinsics::unchecked_mul(power_used, exp) as Self - )}; - // LLVM doesn't always optimize out the checks - // at the ir level. - - let sign = self.is_negative() && exp & 1 != 0; - #[allow(arithmetic_overflow)] - if !sign && res == Self::MIN { - // So it panics. - _ = Self::MAX * Self::MAX; - } - if sign { - res.wrapping_neg() - } else { - res - } - } else { - if exp == 0 { - return 1; - } - let mut base = self; - let mut acc = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = acc * base; - } - exp /= 2; - base = base * base; + while exp > 1 { + if (exp & 1) == 1 { + acc = acc * 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 + 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 d450c68a5b230..a217c2e259d2b 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -1364,49 +1364,28 @@ macro_rules! uint_impl { #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)] #[inline] pub const fn checked_pow(self, mut exp: u32) -> Option { - // SAFETY: This path has the same behavior as the other. - if unsafe { intrinsics::is_val_statically_known(self) } - && self.is_power_of_two() - { - if self == 1 { // Avoid divide by zero - return Some(1); - } - // SAFETY: We just checked this is a power of two. and above zero. - let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 }; - if exp > Self::BITS / power_used { return None; } // Division of constants is free - - // SAFETY: exp <= Self::BITS / power_used - unsafe { Some(intrinsics::unchecked_shl( - 1 as Self, - intrinsics::unchecked_mul(power_used, exp) as Self - )) } - // LLVM doesn't always optimize out the checks - // at the ir level. - } else { - if exp == 0 { - return Some(1); - } - let mut base = self; - let mut acc: Self = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = try_opt!(acc.checked_mul(base)); - } - exp /= 2; - base = try_opt!(base.checked_mul(base)); + if exp == 0 { + return Some(1); + } + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = try_opt!(acc.checked_mul(base)); } + 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. + // 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) - } + acc.checked_mul(base) } /// Strict exponentiation. Computes `self.pow(exp)`, panicking if @@ -1908,48 +1887,27 @@ macro_rules! uint_impl { #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)] #[inline] pub const fn wrapping_pow(self, mut exp: u32) -> Self { - // SAFETY: This path has the same behavior as the other. - if unsafe { intrinsics::is_val_statically_known(self) } - && self.is_power_of_two() - { - if self == 1 { // Avoid divide by zero - return 1; - } - // SAFETY: We just checked this is a power of two. and above zero. - let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 }; - if exp > Self::BITS / power_used { return 0; } // Division of constants is free - - // SAFETY: exp <= Self::BITS / power_used - unsafe { intrinsics::unchecked_shl( - 1 as Self, - intrinsics::unchecked_mul(power_used, exp) as Self - )} - // LLVM doesn't always optimize out the checks - // at the ir level. - } else { - if exp == 0 { - return 1; - } - let mut base = self; - let mut acc: Self = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = acc.wrapping_mul(base); - } - exp /= 2; - base = base.wrapping_mul(base); - } + if exp == 0 { + return 1; + } + let mut base = self; + let mut acc: Self = 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. - acc.wrapping_mul(base) + while exp > 1 { + if (exp & 1) == 1 { + acc = acc.wrapping_mul(base); + } + 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` @@ -2383,58 +2341,37 @@ macro_rules! uint_impl { #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)] #[inline] pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { - // SAFETY: This path has the same behavior as the other. - if unsafe { intrinsics::is_val_statically_known(self) } - && self.is_power_of_two() - { - if self == 1 { // Avoid divide by zero - return (1, false); - } - // SAFETY: We just checked this is a power of two. and above zero. - let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 }; - if exp > Self::BITS / power_used { return (0, true); } // Division of constants is free - - // SAFETY: exp <= Self::BITS / power_used - unsafe { (intrinsics::unchecked_shl( - 1 as Self, - intrinsics::unchecked_mul(power_used, exp) as Self - ), false) } - // LLVM doesn't always optimize out the checks - // at the ir level. - } else { - if exp == 0{ - return (1,false); - } - let mut base = self; - let mut acc: Self = 1; - let mut overflown = false; - // Scratch space for storing results of overflowing_mul. - let mut r; - - while exp > 1 { - if (exp & 1) == 1 { - r = acc.overflowing_mul(base); - acc = r.0; - overflown |= r.1; - } - exp /= 2; - r = base.overflowing_mul(base); - base = r.0; + if exp == 0{ + return (1,false); + } + let mut base = self; + let mut acc: Self = 1; + let mut overflown = false; + // Scratch space for storing results of overflowing_mul. + let mut r; + + while exp > 1 { + if (exp & 1) == 1 { + r = acc.overflowing_mul(base); + acc = r.0; overflown |= r.1; } + exp /= 2; + r = base.overflowing_mul(base); + 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; + // 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 - } + r } /// Raises self to the power of `exp`, using exponentiation by squaring. @@ -2450,64 +2387,28 @@ macro_rules! uint_impl { #[rustc_const_stable(feature = "const_int_pow", since = "1.50.0")] #[must_use = "this returns the result of the operation, \ without modifying the original"] - #[rustc_allow_const_fn_unstable(is_val_statically_known, const_int_unchecked_arith)] #[inline] #[rustc_inherit_overflow_checks] - #[track_caller] // Hides the hackish overflow check for powers of two. pub const fn pow(self, mut exp: u32) -> Self { - // LLVM now knows that `self` is a constant value, but not a - // constant in Rust. This allows us to compute the power used at - // compile-time. - // - // This will likely add a branch in debug builds, but this should - // be ok. - // - // This is a massive performance boost in release builds as you can - // get the power of a power of two and the exponent through a `shl` - // instruction, but we must add a couple more checks for parity with - // our own `pow`. - // SAFETY: This path has the same behavior as the other. - if unsafe { intrinsics::is_val_statically_known(self) } - && self.is_power_of_two() - { - if self == 1 { // Avoid divide by zero - return 1; - } - // SAFETY: We just checked this is a power of two. and above zero. - let power_used = unsafe { intrinsics::cttz_nonzero(self) as u32 }; - if exp > Self::BITS / power_used { // Division of constants is free - #[allow(arithmetic_overflow)] - return Self::MAX * Self::MAX * 0; - } + if exp == 0 { + return 1; + } + let mut base = self; + let mut acc = 1; - // SAFETY: exp <= Self::BITS / power_used - unsafe { intrinsics::unchecked_shl( - 1 as Self, - intrinsics::unchecked_mul(power_used, exp) as Self - )} - // LLVM doesn't always optimize out the checks - // at the ir level. - } else { - if exp == 0 { - return 1; - } - let mut base = self; - let mut acc = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = acc * base; - } - exp /= 2; - base = base * base; + while exp > 1 { + if (exp & 1) == 1 { + acc = acc * 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 + 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/tests/codegen/pow_of_two.rs b/tests/codegen/pow_of_two.rs deleted file mode 100644 index 372360dfd12c7..0000000000000 --- a/tests/codegen/pow_of_two.rs +++ /dev/null @@ -1,55 +0,0 @@ -// compile-flags: --crate-type=lib -Zmerge-functions=disabled -O -C overflow-checks=false - -// CHECK-LABEL: @a( -#[no_mangle] -pub fn a(exp: u32) -> u64 { - // CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 64 - // CHECK: %{{[^ ]+}} = zext{{( nneg)?}} i32 %exp to i64 - // CHECK: %{{[^ ]+}} = shl nuw i64 {{[^ ]+}}, %{{[^ ]+}} - // CHECK: ret i64 %{{[^ ]+}} - 2u64.pow(exp) -} - -// CHECK-LABEL: @b( -#[no_mangle] -pub fn b(exp: u32) -> i64 { - // CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 64 - // CHECK: %{{[^ ]+}} = zext{{( nneg)?}} i32 %exp to i64 - // CHECK: %{{[^ ]+}} = shl nuw i64 {{[^ ]+}}, %{{[^ ]+}} - // CHECK: ret i64 %{{[^ ]+}} - 2i64.pow(exp) -} - -// CHECK-LABEL: @c( -#[no_mangle] -pub fn c(exp: u32) -> u32 { - // CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 16 - // CHECK: %{{[^ ]+}} = shl nuw nsw i32 %exp, 1 - // CHECK: %{{[^ ]+}} = shl nuw i32 1, %{{[^ ]+}} - // CHECK: %{{[^ ]+}} = select i1 %{{[^ ]+}}, i32 0, i32 %{{[^ ]+}} - // CHECK: ret i32 %{{[^ ]+}} - 4u32.pow(exp) -} - -// CHECK-LABEL: @d( -#[no_mangle] -pub fn d(exp: u32) -> u32 { - // CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 6 - // CHECK: %{{[^ ]+}} = mul nuw nsw i32 %exp, 5 - // CHECK: %{{[^ ]+}} = shl nuw nsw i32 1, %{{[^ ]+}} - // CHECK: %{{[^ ]+}} = select i1 {{[^ ]+}}, i32 0, i32 %{{[^ ]+}} - // CHECK: ret i32 %{{[^ ]+}} - 32u32.pow(exp) -} - -// CHECK-LABEL: @e( -#[no_mangle] -pub fn e(exp: u32) -> i32 { - // CHECK: %{{[^ ]+}} = icmp ugt i32 %exp, 6 - // CHECK: %{{[^ ]+}} = mul nuw {{(nsw )?}}i32 %exp, 5 - // CHECK: %{{[^ ]+}} = shl nuw {{(nsw )?}}i32 1, %{{[^ ]+}} - // CHECK: %{{[^ ]+}} = select i1 {{[^ ]+}}, i32 0, i32 %{{[^ ]+}} - // CHECK: ret i32 %{{[^ ]+}} - 32i32.pow(exp) -} -// note: d and e are expected to yield the same IR From c9c049b2b42f4c05ec49fd1c9125fa4333badd3f Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 12 Jan 2024 17:12:45 +1100 Subject: [PATCH 07/28] coverage: Use normal `edition:` headers in coverage tests Some of these tests were originally written as part of a custom `run-make` test, so at that time they weren't able to use the normal compiletest header directive parser. Now that they're properly integrated, there's no need for them to use `compile-flags` to specify the edition, since they can use `edition` instead. --- tests/coverage/bad_counter_ids.cov-map | 32 ++++++++++++------------- tests/coverage/bad_counter_ids.coverage | 3 ++- tests/coverage/bad_counter_ids.rs | 3 ++- tests/coverage/closure_macro.coverage | 2 +- tests/coverage/closure_macro.rs | 2 +- tests/coverage/fn_sig_into_try.coverage | 2 +- tests/coverage/fn_sig_into_try.rs | 2 +- tests/coverage/issue-93054.cov-map | 12 +++++----- tests/coverage/issue-93054.coverage | 3 +-- tests/coverage/issue-93054.rs | 3 +-- tests/coverage/long_and_wide.coverage | 2 +- tests/coverage/long_and_wide.rs | 2 +- tests/coverage/sort_groups.coverage | 2 +- tests/coverage/sort_groups.rs | 2 +- tests/coverage/trivial.coverage | 2 +- tests/coverage/trivial.rs | 2 +- tests/coverage/unreachable.coverage | 2 +- tests/coverage/unreachable.rs | 2 +- 18 files changed, 40 insertions(+), 40 deletions(-) diff --git a/tests/coverage/bad_counter_ids.cov-map b/tests/coverage/bad_counter_ids.cov-map index 3b51e3ef9de66..7eff7f5f02f3c 100644 --- a/tests/coverage/bad_counter_ids.cov-map +++ b/tests/coverage/bad_counter_ids.cov-map @@ -1,81 +1,81 @@ Function name: bad_counter_ids::eq_bad -Raw bytes (14): 0x[01, 01, 00, 02, 01, 23, 01, 02, 1f, 00, 03, 01, 00, 02] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 24, 01, 02, 1f, 00, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 35, 1) to (start + 2, 31) +- Code(Counter(0)) at (prev + 36, 1) to (start + 2, 31) - Code(Zero) at (prev + 3, 1) to (start + 0, 2) Function name: bad_counter_ids::eq_bad_message -Raw bytes (21): 0x[01, 01, 01, 01, 00, 03, 01, 28, 01, 02, 0f, 02, 02, 20, 00, 2b, 00, 01, 01, 00, 02] +Raw bytes (21): 0x[01, 01, 01, 01, 00, 03, 01, 29, 01, 02, 0f, 02, 02, 20, 00, 2b, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Zero Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 40, 1) to (start + 2, 15) +- Code(Counter(0)) at (prev + 41, 1) to (start + 2, 15) - Code(Expression(0, Sub)) at (prev + 2, 32) to (start + 0, 43) = (c0 - Zero) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Function name: bad_counter_ids::eq_good -Raw bytes (14): 0x[01, 01, 00, 02, 01, 0f, 01, 02, 1f, 05, 03, 01, 00, 02] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 01, 02, 1f, 05, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 15, 1) to (start + 2, 31) +- Code(Counter(0)) at (prev + 16, 1) to (start + 2, 31) - Code(Counter(1)) at (prev + 3, 1) to (start + 0, 2) Function name: bad_counter_ids::eq_good_message -Raw bytes (19): 0x[01, 01, 00, 03, 01, 14, 01, 02, 0f, 00, 02, 20, 00, 2b, 05, 01, 01, 00, 02] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 15, 01, 02, 0f, 00, 02, 20, 00, 2b, 05, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 20, 1) to (start + 2, 15) +- Code(Counter(0)) at (prev + 21, 1) to (start + 2, 15) - Code(Zero) at (prev + 2, 32) to (start + 0, 43) - Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2) Function name: bad_counter_ids::ne_bad -Raw bytes (14): 0x[01, 01, 00, 02, 01, 2d, 01, 02, 1f, 00, 03, 01, 00, 02] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 2e, 01, 02, 1f, 00, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 45, 1) to (start + 2, 31) +- Code(Counter(0)) at (prev + 46, 1) to (start + 2, 31) - Code(Zero) at (prev + 3, 1) to (start + 0, 2) Function name: bad_counter_ids::ne_bad_message -Raw bytes (19): 0x[01, 01, 00, 03, 01, 32, 01, 02, 0f, 05, 02, 20, 00, 2b, 00, 01, 01, 00, 02] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 33, 01, 02, 0f, 05, 02, 20, 00, 2b, 00, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 50, 1) to (start + 2, 15) +- Code(Counter(0)) at (prev + 51, 1) to (start + 2, 15) - Code(Counter(1)) at (prev + 2, 32) to (start + 0, 43) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Function name: bad_counter_ids::ne_good -Raw bytes (16): 0x[01, 01, 01, 01, 00, 02, 01, 19, 01, 02, 1f, 02, 03, 01, 00, 02] +Raw bytes (16): 0x[01, 01, 01, 01, 00, 02, 01, 1a, 01, 02, 1f, 02, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Zero Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 25, 1) to (start + 2, 31) +- Code(Counter(0)) at (prev + 26, 1) to (start + 2, 31) - Code(Expression(0, Sub)) at (prev + 3, 1) to (start + 0, 2) = (c0 - Zero) Function name: bad_counter_ids::ne_good_message -Raw bytes (21): 0x[01, 01, 01, 01, 00, 03, 01, 1e, 01, 02, 0f, 00, 02, 20, 00, 2b, 02, 01, 01, 00, 02] +Raw bytes (21): 0x[01, 01, 01, 01, 00, 03, 01, 1f, 01, 02, 0f, 00, 02, 20, 00, 2b, 02, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Zero Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 30, 1) to (start + 2, 15) +- Code(Counter(0)) at (prev + 31, 1) to (start + 2, 15) - Code(Zero) at (prev + 2, 32) to (start + 0, 43) - Code(Expression(0, Sub)) at (prev + 1, 1) to (start + 0, 2) = (c0 - Zero) diff --git a/tests/coverage/bad_counter_ids.coverage b/tests/coverage/bad_counter_ids.coverage index 5474ec2f78552..39e6cae11ddac 100644 --- a/tests/coverage/bad_counter_ids.coverage +++ b/tests/coverage/bad_counter_ids.coverage @@ -1,5 +1,6 @@ LL| |#![feature(coverage_attribute)] - LL| |// compile-flags: --edition=2021 -Copt-level=0 -Zmir-opt-level=3 + LL| |// edition: 2021 + LL| |// compile-flags: -Copt-level=0 -Zmir-opt-level=3 LL| | LL| |// Regression test for . LL| |// diff --git a/tests/coverage/bad_counter_ids.rs b/tests/coverage/bad_counter_ids.rs index ef5460102b70c..e22b96468abd3 100644 --- a/tests/coverage/bad_counter_ids.rs +++ b/tests/coverage/bad_counter_ids.rs @@ -1,5 +1,6 @@ #![feature(coverage_attribute)] -// compile-flags: --edition=2021 -Copt-level=0 -Zmir-opt-level=3 +// edition: 2021 +// compile-flags: -Copt-level=0 -Zmir-opt-level=3 // Regression test for . // diff --git a/tests/coverage/closure_macro.coverage b/tests/coverage/closure_macro.coverage index a6eeb79a71c8f..ab152a91356a0 100644 --- a/tests/coverage/closure_macro.coverage +++ b/tests/coverage/closure_macro.coverage @@ -1,5 +1,5 @@ - LL| |// compile-flags: --edition=2018 LL| |#![feature(coverage_attribute)] + LL| |// edition: 2018 LL| | LL| |macro_rules! bail { LL| | ($msg:literal $(,)?) => { diff --git a/tests/coverage/closure_macro.rs b/tests/coverage/closure_macro.rs index c3ef916788091..38a81ea434b9b 100644 --- a/tests/coverage/closure_macro.rs +++ b/tests/coverage/closure_macro.rs @@ -1,5 +1,5 @@ -// compile-flags: --edition=2018 #![feature(coverage_attribute)] +// edition: 2018 macro_rules! bail { ($msg:literal $(,)?) => { diff --git a/tests/coverage/fn_sig_into_try.coverage b/tests/coverage/fn_sig_into_try.coverage index 71e15fc11eb8a..aac5c9d9a94ee 100644 --- a/tests/coverage/fn_sig_into_try.coverage +++ b/tests/coverage/fn_sig_into_try.coverage @@ -1,5 +1,5 @@ LL| |#![feature(coverage_attribute)] - LL| |// compile-flags: --edition=2021 + LL| |// edition: 2021 LL| | LL| |// Regression test for inconsistent handling of function signature spans that LL| |// are followed by code using the `?` operator. diff --git a/tests/coverage/fn_sig_into_try.rs b/tests/coverage/fn_sig_into_try.rs index 1f4cc67af8386..5d8e7929ef975 100644 --- a/tests/coverage/fn_sig_into_try.rs +++ b/tests/coverage/fn_sig_into_try.rs @@ -1,5 +1,5 @@ #![feature(coverage_attribute)] -// compile-flags: --edition=2021 +// edition: 2021 // Regression test for inconsistent handling of function signature spans that // are followed by code using the `?` operator. diff --git a/tests/coverage/issue-93054.cov-map b/tests/coverage/issue-93054.cov-map index c2c6e9a651673..024ef519fcffe 100644 --- a/tests/coverage/issue-93054.cov-map +++ b/tests/coverage/issue-93054.cov-map @@ -1,24 +1,24 @@ Function name: issue_93054::foo2 (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 16, 01, 00, 1d] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 01, 00, 1d] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 22, 1) to (start + 0, 29) +- Code(Zero) at (prev + 21, 1) to (start + 0, 29) Function name: issue_93054::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1e, 01, 00, 0d] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 1d, 01, 00, 0d] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 30, 1) to (start + 0, 13) +- Code(Counter(0)) at (prev + 29, 1) to (start + 0, 13) Function name: issue_93054::make (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 1a, 01, 02, 02] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 01, 02, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 26, 1) to (start + 2, 2) +- Code(Zero) at (prev + 25, 1) to (start + 2, 2) diff --git a/tests/coverage/issue-93054.coverage b/tests/coverage/issue-93054.coverage index 15f225326a427..6ae8ffb5cb4f2 100644 --- a/tests/coverage/issue-93054.coverage +++ b/tests/coverage/issue-93054.coverage @@ -1,11 +1,10 @@ LL| |#![allow(dead_code, unreachable_code)] + LL| |// edition: 2021 LL| | LL| |// Regression test for #93054: Functions using uninhabited types often only have a single, LL| |// unreachable basic block which doesn't get instrumented. This should not cause llvm-cov to fail. LL| |// Since these kinds functions can't be invoked anyway, it's ok to not have coverage data for them. LL| | - LL| |// compile-flags: --edition=2021 - LL| | LL| |enum Never {} LL| | LL| |impl Never { diff --git a/tests/coverage/issue-93054.rs b/tests/coverage/issue-93054.rs index da546cfeef854..f16fc1e423962 100644 --- a/tests/coverage/issue-93054.rs +++ b/tests/coverage/issue-93054.rs @@ -1,11 +1,10 @@ #![allow(dead_code, unreachable_code)] +// edition: 2021 // Regression test for #93054: Functions using uninhabited types often only have a single, // unreachable basic block which doesn't get instrumented. This should not cause llvm-cov to fail. // Since these kinds functions can't be invoked anyway, it's ok to not have coverage data for them. -// compile-flags: --edition=2021 - enum Never {} impl Never { diff --git a/tests/coverage/long_and_wide.coverage b/tests/coverage/long_and_wide.coverage index d7d29ca40cddd..cf4dd2811406c 100644 --- a/tests/coverage/long_and_wide.coverage +++ b/tests/coverage/long_and_wide.coverage @@ -1,4 +1,4 @@ - LL| |// compile-flags: --edition=2021 + LL| |// edition: 2021 LL| |// ignore-tidy-linelength LL| | LL| |// This file deliberately contains line and column numbers larger than 127, diff --git a/tests/coverage/long_and_wide.rs b/tests/coverage/long_and_wide.rs index a7cbcd4802791..87f2207bd7e67 100644 --- a/tests/coverage/long_and_wide.rs +++ b/tests/coverage/long_and_wide.rs @@ -1,4 +1,4 @@ -// compile-flags: --edition=2021 +// edition: 2021 // ignore-tidy-linelength // This file deliberately contains line and column numbers larger than 127, diff --git a/tests/coverage/sort_groups.coverage b/tests/coverage/sort_groups.coverage index c70d7b3b28253..77cbb09c74a73 100644 --- a/tests/coverage/sort_groups.coverage +++ b/tests/coverage/sort_groups.coverage @@ -1,4 +1,4 @@ - LL| |// compile-flags: --edition=2021 + LL| |// edition: 2021 LL| | LL| |// Demonstrate that `sort_subviews.py` can sort instantiation groups into a LL| |// predictable order, while preserving their heterogeneous contents. diff --git a/tests/coverage/sort_groups.rs b/tests/coverage/sort_groups.rs index 5adbbc6a87d1f..17fd862ca2cad 100644 --- a/tests/coverage/sort_groups.rs +++ b/tests/coverage/sort_groups.rs @@ -1,4 +1,4 @@ -// compile-flags: --edition=2021 +// edition: 2021 // Demonstrate that `sort_subviews.py` can sort instantiation groups into a // predictable order, while preserving their heterogeneous contents. diff --git a/tests/coverage/trivial.coverage b/tests/coverage/trivial.coverage index 4f417979ef97d..af4be7b8f3356 100644 --- a/tests/coverage/trivial.coverage +++ b/tests/coverage/trivial.coverage @@ -1,4 +1,4 @@ - LL| |// compile-flags: --edition=2021 + LL| |// edition: 2021 LL| | LL| 1|fn main() {} diff --git a/tests/coverage/trivial.rs b/tests/coverage/trivial.rs index d0a9b44fb3605..782472739a002 100644 --- a/tests/coverage/trivial.rs +++ b/tests/coverage/trivial.rs @@ -1,3 +1,3 @@ -// compile-flags: --edition=2021 +// edition: 2021 fn main() {} diff --git a/tests/coverage/unreachable.coverage b/tests/coverage/unreachable.coverage index 7015bb90aa38d..a58765f688be5 100644 --- a/tests/coverage/unreachable.coverage +++ b/tests/coverage/unreachable.coverage @@ -1,6 +1,6 @@ LL| |#![feature(core_intrinsics)] LL| |#![feature(coverage_attribute)] - LL| |// compile-flags: --edition=2021 + LL| |// edition: 2021 LL| | LL| |// LL| |// If we instrument a function for coverage, but all of its counter-increment diff --git a/tests/coverage/unreachable.rs b/tests/coverage/unreachable.rs index 6385bfa160d7d..6d0c7b3ca8db5 100644 --- a/tests/coverage/unreachable.rs +++ b/tests/coverage/unreachable.rs @@ -1,6 +1,6 @@ #![feature(core_intrinsics)] #![feature(coverage_attribute)] -// compile-flags: --edition=2021 +// edition: 2021 // // If we instrument a function for coverage, but all of its counter-increment From 3f7b1a5f491a66365e9973babc1b3dde2c90ad55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Thu, 1 Feb 2024 17:59:36 +0100 Subject: [PATCH 08/28] Clean up some things in the name resolver * Get rid of a typo in a function name * Rename `currently_processing_generics`: The old name confused me at first since I assumed it referred to generic *parameters* when it was in fact referring to generic *arguments*. Generics are typically short for generic params. * Get rid of a few unwraps by properly leveraging slice patterns --- compiler/rustc_resolve/src/late.rs | 12 ++++++------ compiler/rustc_resolve/src/late/diagnostics.rs | 16 +++++++++------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 9788fcb3c7d36..1f2803d4368ae 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -594,9 +594,9 @@ struct DiagnosticMetadata<'ast> { /// The current trait (used to suggest). current_item: Option<&'ast Item>, - /// When processing generics and encountering a type not found, suggest introducing a type - /// param. - currently_processing_generics: bool, + /// When processing generic arguments and encountering an unresolved ident not found, + /// suggest introducing a type or const param depending on the context. + currently_processing_generic_args: bool, /// The current enclosing (non-closure) function (used for better errors). current_function: Option<(FnKind<'ast>, Span)>, @@ -1069,7 +1069,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, fn visit_generic_arg(&mut self, arg: &'ast GenericArg) { debug!("visit_generic_arg({:?})", arg); - let prev = replace(&mut self.diagnostic_metadata.currently_processing_generics, true); + let prev = replace(&mut self.diagnostic_metadata.currently_processing_generic_args, true); match arg { GenericArg::Type(ref ty) => { // We parse const arguments as path types as we cannot distinguish them during @@ -1100,7 +1100,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, }, ); - self.diagnostic_metadata.currently_processing_generics = prev; + self.diagnostic_metadata.currently_processing_generic_args = prev; return; } } @@ -1113,7 +1113,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::No)) } } - self.diagnostic_metadata.currently_processing_generics = prev; + self.diagnostic_metadata.currently_processing_generic_args = prev; } fn visit_assoc_constraint(&mut self, constraint: &'ast AssocConstraint) { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index a4c041f1ff247..64e2b6a497151 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -452,7 +452,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } self.suggest_self_or_self_ref(&mut err, path, span); - self.detect_assoct_type_constraint_meant_as_path(&mut err, &base_error); + self.detect_assoc_type_constraint_meant_as_path(&mut err, &base_error); if self.suggest_self_ty(&mut err, source, path, span) || self.suggest_self_value(&mut err, source, path, span) { @@ -491,7 +491,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { (err, candidates) } - fn detect_assoct_type_constraint_meant_as_path( + fn detect_assoc_type_constraint_meant_as_path( &self, err: &mut Diagnostic, base_error: &BaseError, @@ -799,7 +799,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { false, ) = (source, res, is_macro) { - if let Some(bounds @ [_, .., _]) = self.diagnostic_metadata.current_trait_object { + if let Some(bounds @ [first_bound, .., last_bound]) = + self.diagnostic_metadata.current_trait_object + { fallback = true; let spans: Vec = bounds .iter() @@ -807,9 +809,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { .filter(|&sp| sp != base_error.span) .collect(); - let start_span = bounds[0].span(); + let start_span = first_bound.span(); // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><) - let end_span = bounds.last().unwrap().span(); + let end_span = last_bound.span(); // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar) let last_bound_span = spans.last().cloned().unwrap(); let mut multi_span: MultiSpan = spans.clone().into(); @@ -2419,10 +2421,10 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { let mut iter = ident.chars().map(|c| c.is_uppercase()); let single_uppercase_char = matches!(iter.next(), Some(true)) && matches!(iter.next(), None); - if !self.diagnostic_metadata.currently_processing_generics && !single_uppercase_char { + if !self.diagnostic_metadata.currently_processing_generic_args && !single_uppercase_char { return None; } - match (self.diagnostic_metadata.current_item, single_uppercase_char, self.diagnostic_metadata.currently_processing_generics) { + match (self.diagnostic_metadata.current_item, single_uppercase_char, self.diagnostic_metadata.currently_processing_generic_args) { (Some(Item { kind: ItemKind::Fn(..), ident, .. }), _, _) if ident.name == sym::main => { // Ignore `fn main()` as we don't want to suggest `fn main()` } From 5906237b32a83a1df215b87bbafcc926bf49cd66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Fri, 2 Feb 2024 02:49:13 +0100 Subject: [PATCH 09/28] Suggest changing ty to const params if appropriate --- compiler/rustc_resolve/messages.ftl | 3 ++ compiler/rustc_resolve/src/errors.rs | 15 +++++- .../rustc_resolve/src/late/diagnostics.rs | 50 +++++++++++++++++++ .../change-ty-to-const-param-sugg-0.rs | 10 ++++ .../change-ty-to-const-param-sugg-0.stderr | 34 +++++++++++++ .../change-ty-to-const-param-sugg-1.rs | 24 +++++++++ .../change-ty-to-const-param-sugg-1.stderr | 25 ++++++++++ 7 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 tests/ui/resolve/change-ty-to-const-param-sugg-0.rs create mode 100644 tests/ui/resolve/change-ty-to-const-param-sugg-0.stderr create mode 100644 tests/ui/resolve/change-ty-to-const-param-sugg-1.rs create mode 100644 tests/ui/resolve/change-ty-to-const-param-sugg-1.stderr diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index c8ec10cad17c4..02847a0f5f914 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -289,6 +289,9 @@ resolve_underscore_lifetime_name_cannot_be_used_here = `'_` cannot be used here .note = `'_` is a reserved lifetime name +resolve_unexpected_res_change_ty_to_const_param_sugg = + you might have meant to write a const parameter here + resolve_unreachable_label = use of unreachable label `{$name}` .label = unreachable label `{$name}` diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 50ff09feb4d9b..655fc9812d747 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1,4 +1,4 @@ -use rustc_errors::codes::*; +use rustc_errors::{codes::*, Applicability}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{ symbol::{Ident, Symbol}, @@ -787,3 +787,16 @@ pub(crate) struct IsNotDirectlyImportable { pub(crate) span: Span, pub(crate) target: Ident, } + +#[derive(Subdiagnostic)] +#[suggestion( + resolve_unexpected_res_change_ty_to_const_param_sugg, + code = "const ", + style = "verbose" +)] +pub(crate) struct UnexpectedResChangeTyToConstParamSugg { + #[primary_span] + pub span: Span, + #[applicability] + pub applicability: Applicability, +} diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 64e2b6a497151..9f810741f4907 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -444,6 +444,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } self.suggest_bare_struct_literal(&mut err); + self.suggest_changing_type_to_const_param(&mut err, res, source, span); if self.suggest_pattern_match_with_let(&mut err, source, span) { // Fallback label. @@ -1138,6 +1139,55 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { } } + fn suggest_changing_type_to_const_param( + &mut self, + err: &mut Diagnostic, + res: Option, + source: PathSource<'_>, + span: Span, + ) { + let PathSource::Trait(_) = source else { return }; + + // We don't include `DefKind::Str` and `DefKind::AssocTy` as they can't be reached here anyway. + let applicability = match res { + Some(Res::PrimTy(PrimTy::Int(_) | PrimTy::Uint(_) | PrimTy::Bool | PrimTy::Char)) => { + Applicability::MachineApplicable + } + // FIXME(const_generics): Add `DefKind::TyParam` and `SelfTyParam` once we support generic + // const generics. Of course, `Struct` and `Enum` may contain ty params, too, but the + // benefits of including them here outweighs the small number of false positives. + Some(Res::Def(DefKind::Struct | DefKind::Enum, _)) + if self.r.tcx.features().adt_const_params => + { + Applicability::MaybeIncorrect + } + _ => return, + }; + + let Some(item) = self.diagnostic_metadata.current_item else { return }; + let Some(generics) = item.kind.generics() else { return }; + + let param = generics.params.iter().find_map(|param| { + // Only consider type params with exactly one trait bound. + if let [bound] = &*param.bounds + && let ast::GenericBound::Trait(tref, ast::TraitBoundModifiers::NONE) = bound + && tref.span == span + && param.ident.span.eq_ctxt(span) + { + Some(param.ident.span) + } else { + None + } + }); + + if let Some(param) = param { + err.subdiagnostic(errors::UnexpectedResChangeTyToConstParamSugg { + span: param.shrink_to_lo(), + applicability, + }); + } + } + fn suggest_pattern_match_with_let( &mut self, err: &mut Diagnostic, diff --git a/tests/ui/resolve/change-ty-to-const-param-sugg-0.rs b/tests/ui/resolve/change-ty-to-const-param-sugg-0.rs new file mode 100644 index 0000000000000..36fe16f64ebeb --- /dev/null +++ b/tests/ui/resolve/change-ty-to-const-param-sugg-0.rs @@ -0,0 +1,10 @@ +fn make() {} +//~^ ERROR expected trait, found builtin type `u32` +//~| HELP you might have meant to write a const parameter here + +struct Array([bool; N]); +//~^ ERROR expected trait, found builtin type `usize` +//~| HELP you might have meant to write a const parameter here +//~| ERROR expected value, found type parameter `N` + +fn main() {} diff --git a/tests/ui/resolve/change-ty-to-const-param-sugg-0.stderr b/tests/ui/resolve/change-ty-to-const-param-sugg-0.stderr new file mode 100644 index 0000000000000..4e411eae3cbbb --- /dev/null +++ b/tests/ui/resolve/change-ty-to-const-param-sugg-0.stderr @@ -0,0 +1,34 @@ +error[E0404]: expected trait, found builtin type `u32` + --> $DIR/change-ty-to-const-param-sugg-0.rs:1:12 + | +LL | fn make() {} + | ^^^ not a trait + | +help: you might have meant to write a const parameter here + | +LL | fn make() {} + | +++++ + +error[E0404]: expected trait, found builtin type `usize` + --> $DIR/change-ty-to-const-param-sugg-0.rs:5:17 + | +LL | struct Array([bool; N]); + | ^^^^^ not a trait + | +help: you might have meant to write a const parameter here + | +LL | struct Array([bool; N]); + | +++++ + +error[E0423]: expected value, found type parameter `N` + --> $DIR/change-ty-to-const-param-sugg-0.rs:5:31 + | +LL | struct Array([bool; N]); + | - ^ not a value + | | + | found this type parameter + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0404, E0423. +For more information about an error, try `rustc --explain E0404`. diff --git a/tests/ui/resolve/change-ty-to-const-param-sugg-1.rs b/tests/ui/resolve/change-ty-to-const-param-sugg-1.rs new file mode 100644 index 0000000000000..b1d2595f3790f --- /dev/null +++ b/tests/ui/resolve/change-ty-to-const-param-sugg-1.rs @@ -0,0 +1,24 @@ +#![feature(adt_const_params)] +#![allow(incomplete_features)] + +use std::marker::ConstParamTy; + +struct Tagged; +//~^ ERROR expected trait, found enum `Tag` +//~| HELP you might have meant to write a const parameter here +//~| ERROR expected trait, found struct `Options` +//~| HELP you might have meant to write a const parameter here + +#[derive(PartialEq, Eq, ConstParamTy)] +enum Tag { + One, + Two, +} + +#[derive(PartialEq, Eq, ConstParamTy)] +struct Options { + verbose: bool, + safe: bool, +} + +fn main() {} diff --git a/tests/ui/resolve/change-ty-to-const-param-sugg-1.stderr b/tests/ui/resolve/change-ty-to-const-param-sugg-1.stderr new file mode 100644 index 0000000000000..933fac27f8f4e --- /dev/null +++ b/tests/ui/resolve/change-ty-to-const-param-sugg-1.stderr @@ -0,0 +1,25 @@ +error[E0404]: expected trait, found enum `Tag` + --> $DIR/change-ty-to-const-param-sugg-1.rs:6:18 + | +LL | struct Tagged; + | ^^^ not a trait + | +help: you might have meant to write a const parameter here + | +LL | struct Tagged; + | +++++ + +error[E0404]: expected trait, found struct `Options` + --> $DIR/change-ty-to-const-param-sugg-1.rs:6:26 + | +LL | struct Tagged; + | ^^^^^^^ not a trait + | +help: you might have meant to write a const parameter here + | +LL | struct Tagged; + | +++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0404`. From f066be5f2932e791cb766fdf18e9c1fc0d985451 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 2 Feb 2024 13:02:55 +1100 Subject: [PATCH 10/28] Rename `buffer_non_error_diag` as `buffer_non_error`. To match `buffer_error`. --- .../rustc_borrowck/src/diagnostics/outlives_suggestion.rs | 2 +- compiler/rustc_borrowck/src/lib.rs | 6 +++--- compiler/rustc_borrowck/src/nll.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs index ad66c677c78f5..bac1d9dd57f6b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs +++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs @@ -251,6 +251,6 @@ impl OutlivesSuggestionBuilder { diag.sort_span = mir_span.shrink_to_hi(); // Buffer the diagnostic - mbcx.buffer_non_error_diag(diag); + mbcx.buffer_non_error(diag); } } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index ea48e78509b7c..bcd30b3624eb1 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2435,7 +2435,7 @@ mod error { self.buffered.push(t.into_diagnostic()); } - pub fn buffer_non_error_diag(&mut self, t: DiagnosticBuilder<'_, ()>) { + pub fn buffer_non_error(&mut self, t: DiagnosticBuilder<'_, ()>) { self.buffered.push(t.into_diagnostic()); } @@ -2449,8 +2449,8 @@ mod error { self.errors.buffer_error(t); } - pub fn buffer_non_error_diag(&mut self, t: DiagnosticBuilder<'_, ()>) { - self.errors.buffer_non_error_diag(t); + pub fn buffer_non_error(&mut self, t: DiagnosticBuilder<'_, ()>) { + self.errors.buffer_non_error(t); } pub fn buffer_move_error( diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index cc8208e9dc306..f4864986e2811 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -310,7 +310,7 @@ pub(super) fn dump_annotation<'tcx>( err.note(format!("Inferred opaque type values:\n{opaque_type_values:#?}")); } - errors.buffer_non_error_diag(err); + errors.buffer_non_error(err); } fn for_each_region_constraint<'tcx>( From 3a02ebcac27fd730ba89cf1565400d516f296815 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 2 Feb 2024 09:05:53 +1100 Subject: [PATCH 11/28] Remove `BorrowckErrors::set_tainted_by_errors`. It has no effect. Note that `infcx.set_tainted_by_errors()` is still called, so taintedness is still being propagated. --- compiler/rustc_borrowck/src/lib.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index bcd30b3624eb1..c5a87437003c7 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -178,7 +178,6 @@ fn do_mir_borrowck<'tcx>( // Gather the upvars of a closure, if any. if let Some(e) = input_body.tainted_by_errors { infcx.set_tainted_by_errors(e); - errors.set_tainted_by_errors(e); } // Replace all regions with fresh inference variables. This @@ -2438,10 +2437,6 @@ mod error { pub fn buffer_non_error(&mut self, t: DiagnosticBuilder<'_, ()>) { self.buffered.push(t.into_diagnostic()); } - - pub fn set_tainted_by_errors(&mut self, e: ErrorGuaranteed) { - self.tainted_by_errors = Some(e); - } } impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { From 5fd824de449575d3de21f3a6a25104d708665664 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 2 Feb 2024 13:04:07 +1100 Subject: [PATCH 12/28] Remove `BorrowckErrors::tainted_by_errors`. `BorrowckErrors` stores a mix of error and non-error diags in `buffered`. As a result, it downgrades `DiagnosticBuilder`s to `Diagnostic`s, losing the emission guarantees, and so has to use a `tainted_by_errors` field to record whether an error has occurred. This commit splits `buffered` into `buffered_errors` and `buffered_non_errors`, keeping them as `DiagnosticBuilder`s and preserving the emission guarantees. This also requires fixing a bunch of incorrect lifetimes on `DiagnosticBuilder` use points. --- .../rustc_borrowck/src/borrowck_errors.rs | 16 ++-- .../src/diagnostics/conflict_errors.rs | 20 ++--- .../src/diagnostics/move_errors.rs | 4 +- compiler/rustc_borrowck/src/lib.rs | 85 ++++++++++--------- 4 files changed, 66 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 8a275a8363010..6cbcda37f50b8 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -130,7 +130,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { noun_old: &str, old_opt_via: &str, previous_end_span: Option, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { let mut err = struct_span_code_err!( self.dcx(), new_loan_span, @@ -162,7 +162,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { old_opt_via: &str, previous_end_span: Option, second_borrow_desc: &str, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { let mut err = struct_span_code_err!( self.dcx(), new_loan_span, @@ -194,7 +194,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { kind_old: &str, msg_old: &str, old_load_end_span: Option, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") }; let mut err = struct_span_code_err!( self.dcx(), @@ -235,7 +235,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { span: Span, borrow_span: Span, desc: &str, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { struct_span_code_err!( self.dcx(), span, @@ -252,7 +252,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { span: Span, desc: &str, is_arg: bool, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { let msg = if is_arg { "to immutable argument" } else { "twice to immutable variable" }; struct_span_code_err!(self.dcx(), span, E0384, "cannot assign {} {}", msg, desc) } @@ -265,7 +265,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { &self, move_from_span: Span, move_from_desc: &str, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { struct_span_code_err!( self.dcx(), move_from_span, @@ -283,7 +283,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { move_from_span: Span, ty: Ty<'_>, is_index: Option, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { let type_name = match (&ty.kind(), is_index) { (&ty::Array(_, _), Some(true)) | (&ty::Array(_, _), None) => "array", (&ty::Slice(_), _) => "slice", @@ -304,7 +304,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> { &self, move_from_span: Span, container_ty: Ty<'_>, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { struct_span_code_err!( self.dcx(), move_from_span, diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 2e83072b8d132..da5e189024a9b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -327,7 +327,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &mut self, mpi: MovePathIndex, move_span: Span, - err: &mut DiagnosticBuilder<'_>, + err: &mut DiagnosticBuilder<'tcx>, in_pattern: &mut bool, move_spans: UseSpans<'_>, ) { @@ -486,7 +486,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { desired_action: InitializationRequiringAction, span: Span, use_spans: UseSpans<'tcx>, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { // We need all statements in the body where the binding was assigned to later find all // the branching code paths where the binding *wasn't* assigned to. let inits = &self.move_data.init_path_map[mpi]; @@ -880,7 +880,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { location: Location, (place, _span): (Place<'tcx>, Span), borrow: &BorrowData<'tcx>, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { let borrow_spans = self.retrieve_borrow_spans(borrow); let borrow_span = borrow_spans.args_or_use(); @@ -930,7 +930,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { (place, span): (Place<'tcx>, Span), gen_borrow_kind: BorrowKind, issued_borrow: &BorrowData<'tcx>, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { let issued_spans = self.retrieve_borrow_spans(issued_borrow); let issued_span = issued_spans.args_or_use(); @@ -2129,7 +2129,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { drop_span: Span, borrow_spans: UseSpans<'tcx>, explanation: BorrowExplanation<'tcx>, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { debug!( "report_local_value_does_not_live_long_enough(\ {:?}, {:?}, {:?}, {:?}, {:?}\ @@ -2304,7 +2304,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &mut self, drop_span: Span, borrow_span: Span, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { debug!( "report_thread_local_value_does_not_live_long_enough(\ {:?}, {:?}\ @@ -2329,7 +2329,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { borrow_spans: UseSpans<'tcx>, proper_span: Span, explanation: BorrowExplanation<'tcx>, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } = explanation { @@ -2496,7 +2496,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { return_span: Span, category: ConstraintCategory<'tcx>, opt_place_desc: Option<&String>, - ) -> Option> { + ) -> Option> { let return_kind = match category { ConstraintCategory::Return(_) => "return", ConstraintCategory::Yield => "yield", @@ -2591,7 +2591,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { constraint_span: Span, captured_var: &str, scope: &str, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { let tcx = self.infcx.tcx; let args_span = use_span.args_or_use(); @@ -2699,7 +2699,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { upvar_span: Span, upvar_name: Symbol, escape_span: Span, - ) -> DiagnosticBuilder<'cx> { + ) -> DiagnosticBuilder<'tcx> { let tcx = self.infcx.tcx; let escapes_from = tcx.def_descr(self.mir_def_id().to_def_id()); diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index fb3525e8998c0..0a0bb75a2a3a6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -288,7 +288,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { &mut self, place: Place<'tcx>, span: Span, - ) -> DiagnosticBuilder<'a> { + ) -> DiagnosticBuilder<'tcx> { let description = if place.projection.len() == 1 { format!("static item {}", self.describe_any_place(place.as_ref())) } else { @@ -310,7 +310,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { deref_target_place: Place<'tcx>, span: Span, use_spans: Option>, - ) -> DiagnosticBuilder<'a> { + ) -> DiagnosticBuilder<'tcx> { // Inspect the type of the content behind the // borrow to provide feedback about why this // was a move rather than a copy. diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index c5a87437003c7..e3b03717cc87f 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -19,7 +19,7 @@ extern crate tracing; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::graph::dominators::Dominators; -use rustc_errors::{Diagnostic, DiagnosticBuilder}; +use rustc_errors::DiagnosticBuilder; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::{BitSet, ChunkedBitSet}; @@ -173,7 +173,7 @@ fn do_mir_borrowck<'tcx>( } } - let mut errors = error::BorrowckErrors::new(infcx.tcx); + let mut errors = error::BorrowckErrors::new(); // Gather the upvars of a closure, if any. if let Some(e) = input_body.tainted_by_errors { @@ -2124,7 +2124,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | WriteKind::MutableBorrow(BorrowKind::Fake), ) => { if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err() - && !self.has_buffered_errors() + && !self.has_buffered_diags() { // rust-lang/rust#46908: In pure NLL mode this code path should be // unreachable, but we use `span_delayed_bug` because we can hit this when @@ -2387,12 +2387,25 @@ mod error { use super::*; + enum BufferedDiag<'tcx> { + Error(DiagnosticBuilder<'tcx>), + NonError(DiagnosticBuilder<'tcx, ()>), + } + + impl<'tcx> BufferedDiag<'tcx> { + fn sort_span(&self) -> Span { + match self { + BufferedDiag::Error(diag) => diag.sort_span, + BufferedDiag::NonError(diag) => diag.sort_span, + } + } + } + pub struct BorrowckErrors<'tcx> { - tcx: TyCtxt<'tcx>, /// This field keeps track of move errors that are to be reported for given move indices. /// - /// There are situations where many errors can be reported for a single move out (see #53807) - /// and we want only the best of those errors. + /// There are situations where many errors can be reported for a single move out (see + /// #53807) and we want only the best of those errors. /// /// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of @@ -2405,46 +2418,37 @@ mod error { /// same primary span come out in a consistent order. buffered_move_errors: BTreeMap, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>)>, + buffered_mut_errors: FxIndexMap, usize)>, - /// Buffer of diagnostics to be reported. Uses `Diagnostic` rather than `DiagnosticBuilder` - /// because it has a mixture of error diagnostics and non-error diagnostics. - buffered: Vec, - /// Set to Some if we emit an error during borrowck - tainted_by_errors: Option, + + /// Buffer of diagnostics to be reported. A mixture of error and non-error diagnostics. + buffered_diags: Vec>, } impl<'tcx> BorrowckErrors<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>) -> Self { + pub fn new() -> Self { BorrowckErrors { - tcx, buffered_move_errors: BTreeMap::new(), buffered_mut_errors: Default::default(), - buffered: Default::default(), - tainted_by_errors: None, + buffered_diags: Default::default(), } } - pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) { - if let None = self.tainted_by_errors { - self.tainted_by_errors = Some(self.tcx.dcx().span_delayed_bug( - t.span.clone_ignoring_labels(), - "diagnostic buffered but not emitted", - )) - } - self.buffered.push(t.into_diagnostic()); + pub fn buffer_error(&mut self, t: DiagnosticBuilder<'tcx>) { + self.buffered_diags.push(BufferedDiag::Error(t)); } - pub fn buffer_non_error(&mut self, t: DiagnosticBuilder<'_, ()>) { - self.buffered.push(t.into_diagnostic()); + pub fn buffer_non_error(&mut self, t: DiagnosticBuilder<'tcx, ()>) { + self.buffered_diags.push(BufferedDiag::NonError(t)); } } impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { - pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) { + pub fn buffer_error(&mut self, t: DiagnosticBuilder<'tcx>) { self.errors.buffer_error(t); } - pub fn buffer_non_error(&mut self, t: DiagnosticBuilder<'_, ()>) { + pub fn buffer_non_error(&mut self, t: DiagnosticBuilder<'tcx, ()>) { self.errors.buffer_non_error(t); } @@ -2476,38 +2480,41 @@ mod error { } pub fn emit_errors(&mut self) -> Option { + let mut res = None; + // Buffer any move errors that we collected and de-duplicated. for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) { // We have already set tainted for this error, so just buffer it. - self.errors.buffered.push(diag.into_diagnostic()); + self.errors.buffered_diags.push(BufferedDiag::Error(diag)); } for (_, (mut diag, count)) in std::mem::take(&mut self.errors.buffered_mut_errors) { if count > 10 { diag.note(format!("...and {} other attempted mutable borrows", count - 10)); } - self.errors.buffered.push(diag.into_diagnostic()); + self.errors.buffered_diags.push(BufferedDiag::Error(diag)); } - if !self.errors.buffered.is_empty() { - self.errors.buffered.sort_by_key(|diag| diag.sort_span); - - let dcx = self.dcx(); - for diag in self.errors.buffered.drain(..) { - dcx.emit_diagnostic(diag); + if !self.errors.buffered_diags.is_empty() { + self.errors.buffered_diags.sort_by_key(|buffered_diag| buffered_diag.sort_span()); + for buffered_diag in self.errors.buffered_diags.drain(..) { + match buffered_diag { + BufferedDiag::Error(diag) => res = Some(diag.emit()), + BufferedDiag::NonError(diag) => diag.emit(), + } } } - self.errors.tainted_by_errors + res } - pub fn has_buffered_errors(&self) -> bool { - self.errors.buffered.is_empty() + pub(crate) fn has_buffered_diags(&self) -> bool { + self.errors.buffered_diags.is_empty() } pub fn has_move_error( &self, move_out_indices: &[MoveOutIndex], - ) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'cx>)> { + ) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'tcx>)> { self.errors.buffered_move_errors.get(move_out_indices) } } From 2e6bea59688ae65ca7c94ec4f31eb969ac8a9a6e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 2 Feb 2024 13:05:00 +1100 Subject: [PATCH 13/28] Inline and remove `DiagnosticBuilder::into_diagnostic`. It now has a single call site. --- compiler/rustc_errors/src/diagnostic_builder.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 8bfb181648628..faff7f0b52673 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -255,13 +255,8 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { /// Stashes diagnostic for possible later improvement in a different, /// later stage of the compiler. The diagnostic can be accessed with /// the provided `span` and `key` through [`DiagCtxt::steal_diagnostic()`]. - pub fn stash(self, span: Span, key: StashKey) { - self.dcx.stash_diagnostic(span, key, self.into_diagnostic()); - } - - /// Converts the builder to a `Diagnostic` for later emission. - pub fn into_diagnostic(mut self) -> Diagnostic { - self.take_diag() + pub fn stash(mut self, span: Span, key: StashKey) { + self.dcx.stash_diagnostic(span, key, self.take_diag()); } /// Delay emission of this diagnostic as a bug. From b6a4f03306fb2d1965e5d71e5a6f99641a0655ee Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 2 Feb 2024 14:27:34 +1100 Subject: [PATCH 14/28] Rename `BorrowckErrors` as `BorrowckDiags`. And some related things. Because it can hold non-error diagnostics. --- compiler/rustc_borrowck/src/lib.rs | 48 +++++++++++++++--------------- compiler/rustc_borrowck/src/nll.rs | 4 +-- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index e3b03717cc87f..8b5e548345c97 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -173,7 +173,7 @@ fn do_mir_borrowck<'tcx>( } } - let mut errors = error::BorrowckErrors::new(); + let mut diags = diags::BorrowckDiags::new(); // Gather the upvars of a closure, if any. if let Some(e) = input_body.tainted_by_errors { @@ -243,7 +243,7 @@ fn do_mir_borrowck<'tcx>( ®ioncx, &opt_closure_req, &opaque_type_values, - &mut errors, + &mut diags, ); // The various `flow_*` structures can be large. We drop `flow_inits` here @@ -304,11 +304,11 @@ fn do_mir_borrowck<'tcx>( next_region_name: RefCell::new(1), polonius_output: None, move_errors: Vec::new(), - errors, + diags, }; MoveVisitor { ctxt: &mut promoted_mbcx }.visit_body(promoted_body); promoted_mbcx.report_move_errors(); - errors = promoted_mbcx.errors; + diags = promoted_mbcx.diags; struct MoveVisitor<'a, 'cx, 'tcx> { ctxt: &'a mut MirBorrowckCtxt<'cx, 'tcx>, @@ -345,7 +345,7 @@ fn do_mir_borrowck<'tcx>( next_region_name: RefCell::new(1), polonius_output, move_errors: Vec::new(), - errors, + diags, }; // Compute and report region errors, if any. @@ -573,7 +573,7 @@ struct MirBorrowckCtxt<'cx, 'tcx> { /// Results of Polonius analysis. polonius_output: Option>, - errors: error::BorrowckErrors<'tcx>, + diags: diags::BorrowckDiags<'tcx>, move_errors: Vec>, } @@ -2382,7 +2382,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } -mod error { +mod diags { use rustc_errors::ErrorGuaranteed; use super::*; @@ -2401,7 +2401,7 @@ mod error { } } - pub struct BorrowckErrors<'tcx> { + pub struct BorrowckDiags<'tcx> { /// This field keeps track of move errors that are to be reported for given move indices. /// /// There are situations where many errors can be reported for a single move out (see @@ -2425,9 +2425,9 @@ mod error { buffered_diags: Vec>, } - impl<'tcx> BorrowckErrors<'tcx> { + impl<'tcx> BorrowckDiags<'tcx> { pub fn new() -> Self { - BorrowckErrors { + BorrowckDiags { buffered_move_errors: BTreeMap::new(), buffered_mut_errors: Default::default(), buffered_diags: Default::default(), @@ -2445,11 +2445,11 @@ mod error { impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { pub fn buffer_error(&mut self, t: DiagnosticBuilder<'tcx>) { - self.errors.buffer_error(t); + self.diags.buffer_error(t); } pub fn buffer_non_error(&mut self, t: DiagnosticBuilder<'tcx, ()>) { - self.errors.buffer_non_error(t); + self.diags.buffer_non_error(t); } pub fn buffer_move_error( @@ -2458,7 +2458,7 @@ mod error { place_and_err: (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>), ) -> bool { if let Some((_, diag)) = - self.errors.buffered_move_errors.insert(move_out_indices, place_and_err) + self.diags.buffered_move_errors.insert(move_out_indices, place_and_err) { // Cancel the old diagnostic so we don't ICE diag.cancel(); @@ -2472,31 +2472,31 @@ mod error { &mut self, span: Span, ) -> Option<(DiagnosticBuilder<'tcx>, usize)> { - self.errors.buffered_mut_errors.remove(&span) + self.diags.buffered_mut_errors.remove(&span) } pub fn buffer_mut_error(&mut self, span: Span, t: DiagnosticBuilder<'tcx>, count: usize) { - self.errors.buffered_mut_errors.insert(span, (t, count)); + self.diags.buffered_mut_errors.insert(span, (t, count)); } pub fn emit_errors(&mut self) -> Option { let mut res = None; // Buffer any move errors that we collected and de-duplicated. - for (_, (_, diag)) in std::mem::take(&mut self.errors.buffered_move_errors) { + for (_, (_, diag)) in std::mem::take(&mut self.diags.buffered_move_errors) { // We have already set tainted for this error, so just buffer it. - self.errors.buffered_diags.push(BufferedDiag::Error(diag)); + self.diags.buffered_diags.push(BufferedDiag::Error(diag)); } - for (_, (mut diag, count)) in std::mem::take(&mut self.errors.buffered_mut_errors) { + for (_, (mut diag, count)) in std::mem::take(&mut self.diags.buffered_mut_errors) { if count > 10 { diag.note(format!("...and {} other attempted mutable borrows", count - 10)); } - self.errors.buffered_diags.push(BufferedDiag::Error(diag)); + self.diags.buffered_diags.push(BufferedDiag::Error(diag)); } - if !self.errors.buffered_diags.is_empty() { - self.errors.buffered_diags.sort_by_key(|buffered_diag| buffered_diag.sort_span()); - for buffered_diag in self.errors.buffered_diags.drain(..) { + if !self.diags.buffered_diags.is_empty() { + self.diags.buffered_diags.sort_by_key(|buffered_diag| buffered_diag.sort_span()); + for buffered_diag in self.diags.buffered_diags.drain(..) { match buffered_diag { BufferedDiag::Error(diag) => res = Some(diag.emit()), BufferedDiag::NonError(diag) => diag.emit(), @@ -2508,14 +2508,14 @@ mod error { } pub(crate) fn has_buffered_diags(&self) -> bool { - self.errors.buffered_diags.is_empty() + self.diags.buffered_diags.is_empty() } pub fn has_move_error( &self, move_out_indices: &[MoveOutIndex], ) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'tcx>)> { - self.errors.buffered_move_errors.get(move_out_indices) + self.diags.buffered_move_errors.get(move_out_indices) } } } diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index f4864986e2811..7ace013975e1b 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -264,7 +264,7 @@ pub(super) fn dump_annotation<'tcx>( regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option>, opaque_type_values: &FxIndexMap>, - errors: &mut crate::error::BorrowckErrors<'tcx>, + diags: &mut crate::diags::BorrowckDiags<'tcx>, ) { let tcx = infcx.tcx; let base_def_id = tcx.typeck_root_def_id(body.source.def_id()); @@ -310,7 +310,7 @@ pub(super) fn dump_annotation<'tcx>( err.note(format!("Inferred opaque type values:\n{opaque_type_values:#?}")); } - errors.buffer_non_error(err); + diags.buffer_non_error(err); } fn for_each_region_constraint<'tcx>( From 54c4f9489642068e7e75094316deac9a36b25a2f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 1 Feb 2024 15:03:23 +1100 Subject: [PATCH 15/28] Make some fatal errors more concise. --- compiler/rustc_interface/src/interface.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 5ca8809099675..e364d6624bec8 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -54,11 +54,10 @@ pub(crate) fn parse_cfg(dcx: &DiagCtxt, cfgs: Vec) -> Cfg { ($reason: expr) => { #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] - dcx.struct_fatal(format!( + dcx.fatal(format!( concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s - )) - .emit(); + )); }; } @@ -117,11 +116,10 @@ pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec) -> CheckCfg { ($reason:expr) => { #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] - dcx.struct_fatal(format!( + dcx.fatal(format!( concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"), s )) - .emit() }; } From 585367f15f9fe7f4b169f6a157d087c0586c4ee1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 1 Feb 2024 15:09:44 +1100 Subject: [PATCH 16/28] Remove an out-of-date comment. `DiagnosticBuilderInner` was removed some time ago. --- compiler/rustc_errors/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 901fe3fb79930..668c10bc4b6df 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -102,7 +102,6 @@ pub type PResult<'a, T> = Result>; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } // `PResult` is used a lot. Make sure it doesn't unintentionally get bigger. -// (See also the comment on `DiagnosticBuilderInner`'s `diagnostic` field.) #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(PResult<'_, ()>, 16); #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] From a9a2e1565abbeae741d6d715224194caf500099b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 1 Feb 2024 19:17:39 +1100 Subject: [PATCH 17/28] `Diagnostic` cleanups - `emitted_at` isn't used outside the crate. - `code` and `messages` are public fields, so there's no point have trivial getters/setters for them. - `suggestions` is public, so the comment about "functionality on `Diagnostic`" isn't needed. --- compiler/rustc_codegen_llvm/src/errors.rs | 2 +- compiler/rustc_errors/src/diagnostic.rs | 18 +----------------- compiler/rustc_errors/src/lib.rs | 2 +- .../rustc_hir_analysis/src/collect/type_of.rs | 1 - compiler/rustc_hir_typeck/src/pat.rs | 6 +++--- .../infer/error_reporting/note_and_explain.rs | 4 ++-- .../src/traits/error_reporting/suggestions.rs | 2 +- 7 files changed, 9 insertions(+), 26 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index d82ff6656f4d3..e839d278bea7c 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -102,7 +102,7 @@ pub(crate) struct ParseTargetMachineConfig<'a>(pub LlvmError<'a>); impl IntoDiagnostic<'_, G> for ParseTargetMachineConfig<'_> { fn into_diagnostic(self, dcx: &'_ DiagCtxt, level: Level) -> DiagnosticBuilder<'_, G> { let diag: DiagnosticBuilder<'_, G> = self.0.into_diagnostic(dcx, level); - let (message, _) = diag.messages().first().expect("`LlvmError` with no message"); + let (message, _) = diag.messages.first().expect("`LlvmError` with no message"); let message = dcx.eagerly_translate_to_string(message.clone(), diag.args()); DiagnosticBuilder::new(dcx, level, fluent::codegen_llvm_parse_target_machine_config) diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 6deaaef780d41..789889973e2dc 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -116,7 +116,7 @@ pub struct Diagnostic { /// With `-Ztrack_diagnostics` enabled, /// we print where in rustc this error was emitted. - pub emitted_at: DiagnosticLocation, + pub(crate) emitted_at: DiagnosticLocation, } #[derive(Clone, Debug, Encodable, Decodable)] @@ -206,9 +206,6 @@ impl StringPart { } } -// Note: most of these methods are setters that return `&mut Self`. The small -// number of simple getter functions all have `get_` prefixes to distinguish -// them from the setters. impl Diagnostic { #[track_caller] pub fn new>(level: Level, message: M) -> Self { @@ -889,15 +886,6 @@ impl Diagnostic { self } - pub fn clear_code(&mut self) -> &mut Self { - self.code = None; - self - } - - pub fn get_code(&self) -> Option { - self.code - } - pub fn primary_message(&mut self, msg: impl Into) -> &mut Self { self.messages[0] = (msg.into(), Style::NoStyle); self @@ -923,10 +911,6 @@ impl Diagnostic { self.args = args; } - pub fn messages(&self) -> &[(DiagnosticMessage, Style)] { - &self.messages - } - /// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by /// combining it with the primary message of the diagnostic (if translatable, otherwise it just /// passes the user's string along). diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 668c10bc4b6df..61fe00408635d 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1422,7 +1422,7 @@ impl DiagCtxtInner { &mut out, "delayed span bug: {}\n{}\n", bug.inner - .messages() + .messages .iter() .filter_map(|(msg, _)| msg.as_str()) .collect::(), diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 3674a760cbf9d..5cdcc1bb860b2 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -590,7 +590,6 @@ fn infer_placeholder_type<'a>( // The parser provided a sub-optimal `HasPlaceholders` suggestion for the type. // We are typeck and have the real type, so remove that and suggest the actual type. - // FIXME(eddyb) this looks like it should be functionality on `Diagnostic`. if let Ok(suggestions) = &mut err.suggestions { suggestions.clear(); } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index b7f28ef958aa8..fcf4b59e93fcd 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -576,7 +576,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if (lhs, rhs).references_error() { err.downgrade_to_delayed_bug(); } - if self.tcx.sess.teach(err.get_code().unwrap()) { + if self.tcx.sess.teach(err.code.unwrap()) { err.note( "In a match expression, only numbers and characters can be matched \ against a range. This is because the compiler checks that the range \ @@ -847,7 +847,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { type_str ); err.span_label(span, format!("type `{type_str}` cannot be dereferenced")); - if self.tcx.sess.teach(err.get_code().unwrap()) { + if self.tcx.sess.teach(err.code.unwrap()) { err.note(CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ); } return Err(err.emit()); @@ -1669,7 +1669,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } - if tcx.sess.teach(err.get_code().unwrap()) { + if tcx.sess.teach(err.code.unwrap()) { err.note( "This error indicates that a struct pattern attempted to \ extract a nonexistent field from a struct. Struct fields \ diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index 0e7c641e0e0b8..0452d4fe6c806 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -195,7 +195,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } diag.help("type parameters must be constrained to match other types"); - if tcx.sess.teach(diag.get_code().unwrap()) { + if tcx.sess.teach(diag.code.unwrap()) { diag.help( "given a type parameter `T` and a method `foo`: ``` @@ -678,7 +678,7 @@ impl Trait for X { https://doc.rust-lang.org/book/ch19-03-advanced-traits.html", ); } - if tcx.sess.teach(diag.get_code().unwrap()) { + if tcx.sess.teach(diag.code.unwrap()) { diag.help( "given an associated type `T` and a method `foo`: ``` diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 5bab57ca56cb4..2dec27a6126b3 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2717,7 +2717,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let (trait_name, trait_verb) = if name == sym::Send { ("`Send`", "sent") } else { ("`Sync`", "shared") }; - err.clear_code(); + err.code = None; err.primary_message(format!( "{future_or_coroutine} cannot be {trait_verb} between threads safely" )); From 8ba25d0989f8d96cbcb4365fc61b469575e22d63 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 1 Feb 2024 19:18:25 +1100 Subject: [PATCH 18/28] `SilentEmitter::fatal_note` doesn't need to be optional. --- compiler/rustc_errors/src/emitter.rs | 14 ++++++-------- compiler/rustc_interface/src/interface.rs | 8 ++++---- compiler/rustc_session/src/parse.rs | 2 +- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 9f76c1dd248b0..4be5ed923e5e0 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -558,7 +558,7 @@ impl Emitter for HumanEmitter { /// failures of rustc, as witnessed e.g. in issue #89358. pub struct SilentEmitter { pub fatal_dcx: DiagCtxt, - pub fatal_note: Option, + pub fatal_note: String, } impl Translate for SilentEmitter { @@ -576,13 +576,11 @@ impl Emitter for SilentEmitter { None } - fn emit_diagnostic(&mut self, d: &Diagnostic) { - if d.level == Level::Fatal { - let mut d = d.clone(); - if let Some(ref note) = self.fatal_note { - d.note(note.clone()); - } - self.fatal_dcx.emit_diagnostic(d); + fn emit_diagnostic(&mut self, diag: &Diagnostic) { + if diag.level == Level::Fatal { + let mut diag = diag.clone(); + diag.note(self.fatal_note.clone()); + self.fatal_dcx.emit_diagnostic(diag); } } } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index e364d6624bec8..8a4705e0056e1 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -45,9 +45,9 @@ pub struct Compiler { pub(crate) fn parse_cfg(dcx: &DiagCtxt, cfgs: Vec) -> Cfg { cfgs.into_iter() .map(|s| { - let sess = ParseSess::with_silent_emitter(Some(format!( + let sess = ParseSess::with_silent_emitter(format!( "this error occurred on the command line: `--cfg={s}`" - ))); + )); let filename = FileName::cfg_spec_source_code(&s); macro_rules! error { @@ -107,9 +107,9 @@ pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec) -> CheckCfg { let mut check_cfg = CheckCfg { exhaustive_names, exhaustive_values, ..CheckCfg::default() }; for s in specs { - let sess = ParseSess::with_silent_emitter(Some(format!( + let sess = ParseSess::with_silent_emitter(format!( "this error occurred on the command line: `--check-cfg={s}`" - ))); + )); let filename = FileName::cfg_spec_source_code(&s); macro_rules! error { diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 1cfaa49401dac..8adb0cbcc9d76 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -258,7 +258,7 @@ impl ParseSess { } } - pub fn with_silent_emitter(fatal_note: Option) -> Self { + pub fn with_silent_emitter(fatal_note: String) -> Self { let fallback_bundle = fallback_fluent_bundle(Vec::new(), false); let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let fatal_dcx = DiagCtxt::with_tty_emitter(None, fallback_bundle).disable_warnings(); From df322fc29ffc984d488bbaf3a58e95c4002d4b7e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 2 Feb 2024 09:19:22 +1100 Subject: [PATCH 19/28] Remove some unnecessary `clone` calls. --- compiler/rustc_codegen_ssa/src/back/write.rs | 2 +- compiler/rustc_errors/src/lib.rs | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 06edb79453727..eeb251320a781 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1817,7 +1817,7 @@ impl Emitter for SharedEmitter { drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { msgs: diag.messages.clone(), args: args.clone(), - code: diag.code.clone(), + code: diag.code, lvl: diag.level(), }))); for child in &diag.children { diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 61fe00408635d..ac18902866da1 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1252,7 +1252,7 @@ impl DiagCtxtInner { // be stored. Instead, they are buffered until the `LintExpectationId` is replaced by // a stable one by the `LintLevelsBuilder`. if let Some(LintExpectationId::Unstable { .. }) = diagnostic.level.get_expectation_id() { - self.unstable_expect_diagnostics.push(diagnostic.clone()); + self.unstable_expect_diagnostics.push(diagnostic); return None; } @@ -1267,16 +1267,14 @@ impl DiagCtxtInner { DelayedBug(DelayedBugKind::Normal) => { let backtrace = std::backtrace::Backtrace::capture(); self.span_delayed_bugs - .push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace)); - + .push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); #[allow(deprecated)] return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted()); } DelayedBug(DelayedBugKind::GoodPath) => { let backtrace = std::backtrace::Backtrace::capture(); self.good_path_delayed_bugs - .push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace)); - + .push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace)); return None; } _ => {} From 6fdaf3ef7fb5ea72345520a1219ea5cc77d0f71c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 2 Feb 2024 10:14:14 +1100 Subject: [PATCH 20/28] Use `DiagnosticArgName` in a few more places. --- compiler/rustc_codegen_ssa/src/back/write.rs | 3 +-- compiler/rustc_const_eval/src/const_eval/error.rs | 9 ++++----- compiler/rustc_errors/src/diagnostic.rs | 2 +- compiler/rustc_middle/src/error.rs | 7 +++---- compiler/rustc_middle/src/mir/interpret/error.rs | 6 ++++-- compiler/rustc_middle/src/mir/mod.rs | 4 +++- compiler/rustc_middle/src/mir/terminator.rs | 2 +- compiler/rustc_mir_transform/src/const_prop.rs | 2 +- 8 files changed, 18 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index eeb251320a781..4211f875dd01a 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -39,7 +39,6 @@ use rustc_target::spec::{MergeFunctions, SanitizerSet}; use crate::errors::ErrorCreatingRemarkDir; use std::any::Any; -use std::borrow::Cow; use std::fs; use std::io; use std::marker::PhantomData; @@ -1812,7 +1811,7 @@ impl Translate for SharedEmitter { impl Emitter for SharedEmitter { fn emit_diagnostic(&mut self, diag: &rustc_errors::Diagnostic) { - let args: FxHashMap, DiagnosticArgValue> = + let args: FxHashMap = diag.args().map(|(name, arg)| (name.clone(), arg.clone())).collect(); drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic { msgs: diag.messages.clone(), diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index dabf78ef90e5f..1ebc82ad6d4b2 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -1,6 +1,8 @@ use std::mem; -use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, IntoDiagnostic, IntoDiagnosticArg}; +use rustc_errors::{ + DiagnosticArgName, DiagnosticArgValue, DiagnosticMessage, IntoDiagnostic, IntoDiagnosticArg, +}; use rustc_hir::CRATE_HIR_ID; use rustc_middle::mir::AssertKind; use rustc_middle::query::TyCtxtAt; @@ -32,10 +34,7 @@ impl MachineStopType for ConstEvalErrKind { AssertFailure(x) => x.diagnostic_message(), } } - fn add_args( - self: Box, - adder: &mut dyn FnMut(std::borrow::Cow<'static, str>, DiagnosticArgValue), - ) { + fn add_args(self: Box, adder: &mut dyn FnMut(DiagnosticArgName, DiagnosticArgValue)) { use ConstEvalErrKind::*; match *self { ConstAccessesStatic | ModifiedGlobal => {} diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 789889973e2dc..5579b50e85a90 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -900,7 +900,7 @@ impl Diagnostic { pub fn arg( &mut self, - name: impl Into>, + name: impl Into, arg: impl IntoDiagnosticArg, ) -> &mut Self { self.args.insert(name.into(), arg.into_diagnostic_arg()); diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index 211da80020297..3ebbcd650302f 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -1,7 +1,6 @@ -use std::borrow::Cow; use std::fmt; -use rustc_errors::{codes::*, DiagnosticArgValue, DiagnosticMessage}; +use rustc_errors::{codes::*, DiagnosticArgName, DiagnosticArgValue, DiagnosticMessage}; use rustc_macros::Diagnostic; use rustc_span::{Span, Symbol}; @@ -95,14 +94,14 @@ pub(super) struct ConstNotUsedTraitAlias { pub struct CustomSubdiagnostic<'a> { pub msg: fn() -> DiagnosticMessage, - pub add_args: Box, DiagnosticArgValue)) + 'a>, + pub add_args: Box, } impl<'a> CustomSubdiagnostic<'a> { pub fn label(x: fn() -> DiagnosticMessage) -> Self { Self::label_and_then(x, |_| {}) } - pub fn label_and_then, DiagnosticArgValue)) + 'a>( + pub fn label_and_then( msg: fn() -> DiagnosticMessage, f: F, ) -> Self { diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 95574aee499f2..0f69ab93452f7 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -5,7 +5,9 @@ use crate::mir::{ConstAlloc, ConstValue}; use crate::ty::{layout, tls, Ty, TyCtxt, ValTree}; use rustc_data_structures::sync::Lock; -use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg}; +use rustc_errors::{ + DiagnosticArgName, DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg, +}; use rustc_macros::HashStable; use rustc_session::CtfeBacktrace; use rustc_span::{def_id::DefId, Span, DUMMY_SP}; @@ -485,7 +487,7 @@ pub trait MachineStopType: Any + fmt::Debug + Send { fn diagnostic_message(&self) -> DiagnosticMessage; /// Add diagnostic arguments by passing name and value pairs to `adder`, which are passed to /// fluent for formatting the translated diagnostic message. - fn add_args(self: Box, adder: &mut dyn FnMut(Cow<'static, str>, DiagnosticArgValue)); + fn add_args(self: Box, adder: &mut dyn FnMut(DiagnosticArgName, DiagnosticArgValue)); } impl dyn MachineStopType { diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 37c5bba46a7d8..c9e69253701c5 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -14,7 +14,9 @@ use crate::ty::{AdtDef, InstanceDef, UserTypeAnnotationIndex}; use crate::ty::{GenericArg, GenericArgsRef}; use rustc_data_structures::captures::Captures; -use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg}; +use rustc_errors::{ + DiagnosticArgName, DiagnosticArgValue, DiagnosticMessage, ErrorGuaranteed, IntoDiagnosticArg, +}; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; use rustc_hir::{self, CoroutineDesugaring, CoroutineKind, ImplicitSelfKind}; diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 0fe33e441f430..91b7952bec5e8 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -292,7 +292,7 @@ impl AssertKind { } } - pub fn add_args(self, adder: &mut dyn FnMut(Cow<'static, str>, DiagnosticArgValue)) + pub fn add_args(self, adder: &mut dyn FnMut(DiagnosticArgName, DiagnosticArgValue)) where O: fmt::Debug, { diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index c49f92f4f859f..eba62aae60f75 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -34,7 +34,7 @@ pub(crate) macro throw_machine_stop_str($($tt:tt)*) {{ fn add_args( self: Box, - _: &mut dyn FnMut(std::borrow::Cow<'static, str>, rustc_errors::DiagnosticArgValue), + _: &mut dyn FnMut(rustc_errors::DiagnosticArgName, rustc_errors::DiagnosticArgValue), ) {} } throw_machine_stop!(Zst) From cd4c5cd8b8ca96ba1a5a48d287140a85e3984a8b Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 2 Feb 2024 10:15:03 +1100 Subject: [PATCH 21/28] Improve a local variable name. --- compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 0a6b758efa564..5eb85d59feef9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -198,12 +198,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { { let span = self.body.local_decls[local].source_info.span; mut_error = Some(span); - if let Some((buffer, c)) = self.get_buffered_mut_error(span) { + if let Some((buffered_err, c)) = self.get_buffered_mut_error(span) { // We've encountered a second (or more) attempt to mutably borrow an // immutable binding, so the likely problem is with the binding // declaration, not the use. We collect these in a single diagnostic // and make the binding the primary span of the error. - err = buffer; + err = buffered_err; count = c + 1; if count == 2 { err.replace_span_with(span, false); From b506cce5792d543cf5ffa828f539c950b9739b2c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 2 Feb 2024 10:15:53 +1100 Subject: [PATCH 22/28] Fix an incorrect comment. --- compiler/rustc_parse/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 49e036c380133..d5fa11086872f 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -39,7 +39,7 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" } // uses a HOF to parse anything, and includes file and // `source_str`. -/// A variant of 'panictry!' that works on a `Vec` instead of a single +/// A variant of 'panictry!' that works on a `Vec` instead of a single /// `DiagnosticBuilder`. macro_rules! panictry_buffer { ($e:expr) => {{ From 0621cd46f2ee2711cf2f808521629d223fda8d54 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 2 Feb 2024 14:30:37 +1100 Subject: [PATCH 23/28] Simplify future breakage control flow. `emit_future_breakage` calls `self.dcx().take_future_breakage_diagnostics()` and then passes the result to `self.dcx().emit_future_breakage_report(diags)`. This commit removes the first of these and lets `emit_future_breakage_report` do the taking. It also inlines and removes what is left of `emit_future_breakage`, which has a single call site. --- compiler/rustc_errors/src/lib.rs | 12 ++++++------ compiler/rustc_session/src/session.rs | 14 ++------------ 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index ac18902866da1..699691c5dabc3 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1038,10 +1038,6 @@ impl DiagCtxt { } } - pub fn take_future_breakage_diagnostics(&self) -> Vec { - std::mem::take(&mut self.inner.borrow_mut().future_breakage_diagnostics) - } - pub fn abort_if_errors(&self) { let mut inner = self.inner.borrow_mut(); inner.emit_stashed_diagnostics(); @@ -1149,8 +1145,12 @@ impl DiagCtxt { self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type); } - pub fn emit_future_breakage_report(&self, diags: Vec) { - self.inner.borrow_mut().emitter.emit_future_breakage_report(diags) + pub fn emit_future_breakage_report(&self) { + let mut inner = self.inner.borrow_mut(); + let diags = std::mem::take(&mut inner.future_breakage_diagnostics); + if !diags.is_empty() { + inner.emitter.emit_future_breakage_report(diags); + } } pub fn emit_unused_externs( diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 3a0ae74dd9215..f6af5a4f87e07 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -288,19 +288,9 @@ impl Session { pub fn finish_diagnostics(&self, registry: &Registry) { self.check_miri_unleashed_features(); self.dcx().print_error_count(registry); - self.emit_future_breakage(); - } - - fn emit_future_breakage(&self) { - if !self.opts.json_future_incompat { - return; - } - - let diags = self.dcx().take_future_breakage_diagnostics(); - if diags.is_empty() { - return; + if self.opts.json_future_incompat { + self.dcx().emit_future_breakage_report(); } - self.dcx().emit_future_breakage_report(diags); } /// Returns true if the crate is a testing one. From be648028547291dfe64938a0c059640a629ea0b2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Sat, 3 Feb 2024 09:02:36 +1100 Subject: [PATCH 24/28] Use `StringPart` more. --- compiler/rustc_errors/src/diagnostic.rs | 55 +++++++++---------- compiler/rustc_errors/src/lib.rs | 2 +- .../error_reporting/type_err_ctxt_ext.rs | 24 ++++---- 3 files changed, 38 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 5579b50e85a90..8ad4925cff288 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -165,10 +165,10 @@ impl DiagnosticStyledString { DiagnosticStyledString(vec![]) } pub fn push_normal>(&mut self, t: S) { - self.0.push(StringPart::normal(t.into())); + self.0.push(StringPart::normal(t)); } pub fn push_highlighted>(&mut self, t: S) { - self.0.push(StringPart::highlighted(t.into())); + self.0.push(StringPart::highlighted(t)); } pub fn push>(&mut self, t: S, highlight: bool) { if highlight { @@ -178,11 +178,11 @@ impl DiagnosticStyledString { } } pub fn normal>(t: S) -> DiagnosticStyledString { - DiagnosticStyledString(vec![StringPart::normal(t.into())]) + DiagnosticStyledString(vec![StringPart::normal(t)]) } pub fn highlighted>(t: S) -> DiagnosticStyledString { - DiagnosticStyledString(vec![StringPart::highlighted(t.into())]) + DiagnosticStyledString(vec![StringPart::highlighted(t)]) } pub fn content(&self) -> String { @@ -197,12 +197,12 @@ pub struct StringPart { } impl StringPart { - fn normal(content: String) -> StringPart { - StringPart { content, style: Style::NoStyle } + pub fn normal>(content: S) -> StringPart { + StringPart { content: content.into(), style: Style::NoStyle } } - fn highlighted(content: String) -> StringPart { - StringPart { content, style: Style::Highlight } + pub fn highlighted>(content: S) -> StringPart { + StringPart { content: content.into(), style: Style::Highlight } } } @@ -391,13 +391,16 @@ impl Diagnostic { } else { (0, found_label.len() - expected_label.len()) }; - let mut msg: Vec<_> = - vec![(format!("{}{} `", " ".repeat(expected_padding), expected_label), Style::NoStyle)]; - msg.extend(expected.0.into_iter().map(|p| (p.content, p.style))); - msg.push((format!("`{expected_extra}\n"), Style::NoStyle)); - msg.push((format!("{}{} `", " ".repeat(found_padding), found_label), Style::NoStyle)); - msg.extend(found.0.into_iter().map(|p| (p.content, p.style))); - msg.push((format!("`{found_extra}"), Style::NoStyle)); + let mut msg = vec![StringPart::normal(format!( + "{}{} `", + " ".repeat(expected_padding), + expected_label + ))]; + msg.extend(expected.0.into_iter()); + msg.push(StringPart::normal(format!("`{expected_extra}\n"))); + msg.push(StringPart::normal(format!("{}{} `", " ".repeat(found_padding), found_label))); + msg.extend(found.0.into_iter()); + msg.push(StringPart::normal(format!("`{found_extra}"))); // For now, just attach these as notes. self.highlighted_note(msg); @@ -406,9 +409,9 @@ impl Diagnostic { pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut Self { self.highlighted_note(vec![ - (format!("`{name}` from trait: `"), Style::NoStyle), - (signature, Style::Highlight), - ("`".to_string(), Style::NoStyle), + StringPart::normal(format!("`{name}` from trait: `")), + StringPart::highlighted(signature), + StringPart::normal("`"), ]); self } @@ -420,10 +423,7 @@ impl Diagnostic { self } - fn highlighted_note>( - &mut self, - msg: Vec<(M, Style)>, - ) -> &mut Self { + fn highlighted_note(&mut self, msg: Vec) -> &mut Self { self.sub_with_highlights(Level::Note, msg, MultiSpan::new()); self } @@ -492,7 +492,7 @@ impl Diagnostic { } /// Add a help message attached to this diagnostic with a customizable highlighted message. - pub fn highlighted_help(&mut self, msg: Vec<(String, Style)>) -> &mut Self { + pub fn highlighted_help(&mut self, msg: Vec) -> &mut Self { self.sub_with_highlights(Level::Help, msg, MultiSpan::new()); self } @@ -941,15 +941,10 @@ impl Diagnostic { /// Convenience function for internal use, clients should use one of the /// public methods above. - fn sub_with_highlights>( - &mut self, - level: Level, - messages: Vec<(M, Style)>, - span: MultiSpan, - ) { + fn sub_with_highlights(&mut self, level: Level, messages: Vec, span: MultiSpan) { let messages = messages .into_iter() - .map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.0), m.1)) + .map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.content), m.style)) .collect(); let sub = SubDiagnostic { level, messages, span }; self.children.push(sub); diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 699691c5dabc3..b2bd4d8eb956e 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -34,7 +34,7 @@ extern crate self as rustc_errors; pub use codes::*; pub use diagnostic::{ AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgName, - DiagnosticArgValue, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic, + DiagnosticArgValue, DiagnosticStyledString, IntoDiagnosticArg, StringPart, SubDiagnostic, }; pub use diagnostic_builder::{ BugAbort, DiagnosticBuilder, EmissionGuarantee, FatalAbort, IntoDiagnostic, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index dee3e14f3c918..d9c5de17af885 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -20,7 +20,7 @@ use crate::traits::{ use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::{ codes::*, pluralize, struct_span_code_err, Applicability, Diagnostic, DiagnosticBuilder, - ErrorGuaranteed, MultiSpan, StashKey, Style, + ErrorGuaranteed, MultiSpan, StashKey, StringPart, }; use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace, Res}; @@ -2059,11 +2059,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ct_op: |ct| ct.normalize(self.tcx, ty::ParamEnv::empty()), }); err.highlighted_help(vec![ - (format!("the trait `{}` ", cand.print_trait_sugared()), Style::NoStyle), - ("is".to_string(), Style::Highlight), - (" implemented for `".to_string(), Style::NoStyle), - (cand.self_ty().to_string(), Style::Highlight), - ("`".to_string(), Style::NoStyle), + StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())), + StringPart::highlighted("is"), + StringPart::normal(" implemented for `"), + StringPart::highlighted(cand.self_ty().to_string()), + StringPart::normal("`"), ]); if let [TypeError::Sorts(exp_found)] = &terrs[..] { @@ -2095,12 +2095,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { _ => (" implemented for `", ""), }; err.highlighted_help(vec![ - (format!("the trait `{}` ", cand.print_trait_sugared()), Style::NoStyle), - ("is".to_string(), Style::Highlight), - (desc.to_string(), Style::NoStyle), - (cand.self_ty().to_string(), Style::Highlight), - ("`".to_string(), Style::NoStyle), - (mention_castable.to_string(), Style::NoStyle), + StringPart::normal(format!("the trait `{}` ", cand.print_trait_sugared())), + StringPart::highlighted("is"), + StringPart::normal(desc), + StringPart::highlighted(cand.self_ty().to_string()), + StringPart::normal("`"), + StringPart::normal(mention_castable), ]); return true; } From ef37dcb7dbb444751b825adb55f2246b4fa3a52b Mon Sep 17 00:00:00 2001 From: trevyn <230691+trevyn@users.noreply.github.com> Date: Fri, 2 Feb 2024 15:16:05 -0800 Subject: [PATCH 25/28] Remove unnecessary `.to_string()`/`.as_str()`s --- compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs | 2 +- .../rustc_borrowck/src/diagnostics/mutability_errors.rs | 2 +- compiler/rustc_hir_analysis/src/astconv/errors.rs | 2 +- compiler/rustc_hir_typeck/src/expr.rs | 2 +- compiler/rustc_hir_typeck/src/method/suggest.rs | 6 +++--- compiler/rustc_parse/src/parser/expr.rs | 2 +- compiler/rustc_parse/src/parser/generics.rs | 2 +- compiler/rustc_parse/src/parser/item.rs | 2 +- compiler/rustc_resolve/src/late/diagnostics.rs | 4 ++-- .../src/traits/error_reporting/suggestions.rs | 6 +++--- 10 files changed, 15 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 2e83072b8d132..c77479d66604e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2440,7 +2440,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "consider consuming the `{ty}` when turning it into an \ `Iterator`", ), - "into_iter".to_string(), + "into_iter", Applicability::MaybeIncorrect, ); } diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 0a6b758efa564..aa2503a29ab95 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -924,7 +924,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { err.span_suggestion_verbose( expr.span.shrink_to_lo(), "use a mutable iterator instead", - "mut ".to_string(), + "mut ", Applicability::MachineApplicable, ); } diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index 407517b15ef5e..e67a44d96ad43 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -247,7 +247,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { err.span_suggestion_verbose( assoc_name.span, fluent::hir_analysis_assoc_item_not_found_similar_in_other_trait_with_bound_sugg, - suggested_name.to_string(), + suggested_name, Applicability::MaybeIncorrect, ); } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 2bbef11fa2450..1adde8c21b8e2 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1000,7 +1000,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_suggestion_verbose( lhs.span.shrink_to_hi(), "you might have meant to write a semicolon here", - ";".to_string(), + ";", Applicability::MachineApplicable, ); return true; diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 6c9501e93fa11..904961d9eba26 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1116,9 +1116,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_name.span, format!( "you might have meant to use `{}`", - inherent_method.name.as_str() + inherent_method.name ), - inherent_method.name.as_str(), + inherent_method.name, Applicability::MaybeIncorrect, ); break 'outer; @@ -2019,7 +2019,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { diag.span_suggestion_verbose( sm.span_extend_while(seg1.ident.span.shrink_to_hi(), |c| c == ':').unwrap(), "you may have meant to call an instance method", - ".".to_string(), + ".", Applicability::MaybeIncorrect, ); } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 9f748e2a3feb1..e36a648e2032e 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3288,7 +3288,7 @@ impl<'a> Parser<'a> { } else { Applicability::MaybeIncorrect }; - err.span_suggestion_verbose(sugg_sp, msg, "=> ".to_string(), applicability); + err.span_suggestion_verbose(sugg_sp, msg, "=> ", applicability); } } err diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 48cf04f7790d0..e059e7074910a 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -148,7 +148,7 @@ impl<'a> Parser<'a> { .with_span_suggestion_verbose( mistyped_const_ident.span, "use the `const` keyword", - kw::Const.as_str(), + kw::Const, Applicability::MachineApplicable, ) .emit(); diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 9a77643f9510f..8050b34956ce9 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1453,7 +1453,7 @@ impl<'a> Parser<'a> { err.span_suggestion_verbose( prev_span, "perhaps you meant to use `struct` here", - "struct".to_string(), + "struct", Applicability::MaybeIncorrect, ); } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index a4c041f1ff247..c2228edb97458 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -699,7 +699,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { err.span_suggestion_verbose( span.shrink_to_lo(), msg, - "self.".to_string(), + "self.", Applicability::MachineApplicable, ); } @@ -710,7 +710,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { err.span_suggestion_verbose( span.shrink_to_lo(), format!("you might have meant to {}", candidate.action()), - "Self::".to_string(), + "Self::", Applicability::MachineApplicable, ); } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 5bab57ca56cb4..a49c446aa0fb2 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1288,7 +1288,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.span_suggestion_verbose( obligation.cause.span.shrink_to_hi(), "consider using clone here", - ".clone()".to_string(), + ".clone()", Applicability::MaybeIncorrect, ); return true; @@ -3245,7 +3245,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.span_suggestion_verbose( span, "you can use `impl Trait` as the argument type", - "impl ".to_string(), + "impl ", Applicability::MaybeIncorrect, ); let sugg = if !needs_parens { @@ -5203,7 +5203,7 @@ fn point_at_assoc_type_restriction( err.span_suggestion_verbose( path.span, "replace the associated type with the type specified in this `impl`", - tcx.type_of(new.def_id).skip_binder().to_string(), + tcx.type_of(new.def_id).skip_binder(), Applicability::MachineApplicable, ); } From c5eca333fc8ad2b3f7d45d3a0af59d1cf83df23c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 3 Feb 2024 15:50:14 +0300 Subject: [PATCH 26/28] hir: Remove the generic type parameter from `MaybeOwned` It's only ever used with a reference to `OwnerInfo` as an argument. --- compiler/rustc_ast_lowering/src/item.rs | 7 ++----- compiler/rustc_ast_lowering/src/lib.rs | 4 ++-- compiler/rustc_hir/src/hir.rs | 25 +++++++----------------- compiler/rustc_middle/src/hir/mod.rs | 9 ++++----- compiler/rustc_middle/src/query/erase.rs | 4 ++-- 5 files changed, 17 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index dd3f7289a60b2..6b772c1295f55 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -25,7 +25,7 @@ pub(super) struct ItemLowerer<'a, 'hir> { pub(super) tcx: TyCtxt<'hir>, pub(super) resolver: &'a mut ResolverAstLowering, pub(super) ast_index: &'a IndexSlice>, - pub(super) owners: &'a mut IndexVec>>, + pub(super) owners: &'a mut IndexVec>, } /// When we have a ty alias we *may* have two where clauses. To give the best diagnostics, we set the span @@ -64,10 +64,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { } } - pub(super) fn lower_node( - &mut self, - def_id: LocalDefId, - ) -> hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>> { + pub(super) fn lower_node(&mut self, def_id: LocalDefId) -> hir::MaybeOwner<'hir> { let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); if let hir::MaybeOwner::Phantom = owner { let node = self.ast_index[def_id]; diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 3621844efc8d2..f26b1331ef388 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -99,7 +99,7 @@ struct LoweringContext<'a, 'hir> { /// Attributes inside the owner being lowered. attrs: SortedMap, /// Collect items that were created by lowering the current owner. - children: Vec<(LocalDefId, hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>>)>, + children: Vec<(LocalDefId, hir::MaybeOwner<'hir>)>, coroutine_kind: Option, @@ -415,7 +415,7 @@ fn index_crate<'a>( /// This hash will then be part of the crate_hash which is stored in the metadata. fn compute_hir_hash( tcx: TyCtxt<'_>, - owners: &IndexSlice>>, + owners: &IndexSlice>, ) -> Fingerprint { let mut hir_body_nodes: Vec<_> = owners .iter_enumerated() diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 681e228a0f2ff..de1b28acb1267 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -894,34 +894,23 @@ impl<'tcx> OwnerInfo<'tcx> { } #[derive(Copy, Clone, Debug, HashStable_Generic)] -pub enum MaybeOwner { - Owner(T), +pub enum MaybeOwner<'tcx> { + Owner(&'tcx OwnerInfo<'tcx>), NonOwner(HirId), /// Used as a placeholder for unused LocalDefId. Phantom, } -impl MaybeOwner { - pub fn as_owner(self) -> Option { +impl<'tcx> MaybeOwner<'tcx> { + pub fn as_owner(self) -> Option<&'tcx OwnerInfo<'tcx>> { match self { MaybeOwner::Owner(i) => Some(i), MaybeOwner::NonOwner(_) | MaybeOwner::Phantom => None, } } - pub fn map(self, f: impl FnOnce(T) -> U) -> MaybeOwner { - match self { - MaybeOwner::Owner(i) => MaybeOwner::Owner(f(i)), - MaybeOwner::NonOwner(hir_id) => MaybeOwner::NonOwner(hir_id), - MaybeOwner::Phantom => MaybeOwner::Phantom, - } - } - - pub fn unwrap(self) -> T { - match self { - MaybeOwner::Owner(i) => i, - MaybeOwner::NonOwner(_) | MaybeOwner::Phantom => panic!("Not a HIR owner"), - } + pub fn unwrap(self) -> &'tcx OwnerInfo<'tcx> { + self.as_owner().unwrap_or_else(|| panic!("Not a HIR owner")) } } @@ -933,7 +922,7 @@ impl MaybeOwner { /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html #[derive(Debug)] pub struct Crate<'hir> { - pub owners: IndexVec>>, + pub owners: IndexVec>, // Only present when incr. comp. is enabled. pub opt_hir_hash: Option, } diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index b54e438f6144d..94191df30a5e6 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -127,12 +127,11 @@ pub fn provide(providers: &mut Providers) { providers.hir_crate_items = map::hir_crate_items; providers.crate_hash = map::crate_hash; providers.hir_module_items = map::hir_module_items; - providers.opt_local_def_id_to_hir_id = |tcx, id| { - let owner = tcx.hir_crate(()).owners[id].map(|_| ()); - Some(match owner { - MaybeOwner::Owner(_) => HirId::make_owner(id), - MaybeOwner::Phantom => bug!("No HirId for {:?}", id), + providers.opt_local_def_id_to_hir_id = |tcx, def_id| { + Some(match tcx.hir_crate(()).owners[def_id] { + MaybeOwner::Owner(_) => HirId::make_owner(def_id), MaybeOwner::NonOwner(hir_id) => hir_id, + MaybeOwner::Phantom => bug!("No HirId for {:?}", def_id), }) }; providers.opt_hir_owner_nodes = diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 1b01df6a18714..a272a51f32747 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -185,8 +185,8 @@ impl EraseType for Option>> { type Result = [u8; size_of::>>>()]; } -impl EraseType for rustc_hir::MaybeOwner<&'_ T> { - type Result = [u8; size_of::>()]; +impl EraseType for rustc_hir::MaybeOwner<'_> { + type Result = [u8; size_of::>()]; } impl EraseType for ty::EarlyBinder { From 8f1573a5853898dbb8196b287c670e79d4c4705b Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Mon, 15 Jan 2024 15:51:53 -0500 Subject: [PATCH 27/28] Release notes for 1.76 --- RELEASES.md | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 3fb74b52292c1..038a83cde84d6 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,96 @@ +Version 1.76.0 (2024-02-08) +========================== + + + +Language +-------- +- [Document Rust ABI compatibility between various types](https://github.com/rust-lang/rust/pull/115476/) +- [Also: guarantee that char and u32 are ABI-compatible](https://github.com/rust-lang/rust/pull/118032/) +- [Warn against ambiguous wide pointer comparisons](https://github.com/rust-lang/rust/pull/117758/) + + + +Compiler +-------- +- [Lint pinned `#[must_use]` pointers (in particular, `Box` where `T` is `#[must_use]`) in `unused_must_use`.](https://github.com/rust-lang/rust/pull/118054/) +- [Soundness fix: fix computing the offset of an unsized field in a packed struct](https://github.com/rust-lang/rust/pull/118540/) +- [Soundness fix: fix dynamic size/align computation logic for packed types with dyn Trait tail](https://github.com/rust-lang/rust/pull/118538/) +- [Add `$message_type` field to distinguish json diagnostic outputs](https://github.com/rust-lang/rust/pull/115691/) +- [Enable Rust to use the EHCont security feature of Windows](https://github.com/rust-lang/rust/pull/118013/) +- [Add tier 3 {x86_64,i686}-win7-windows-msvc targets](https://github.com/rust-lang/rust/pull/118150/) +- [Add tier 3 aarch64-apple-watchos target](https://github.com/rust-lang/rust/pull/119074/) +- [Add tier 3 arm64e-apple-ios & arm64e-apple-darwin targets](https://github.com/rust-lang/rust/pull/115526/) + +Refer to Rust's [platform support page][platform-support-doc] +for more information on Rust's tiered platform support. + + + +Libraries +--------- +- [Add a column number to `dbg!()`](https://github.com/rust-lang/rust/pull/114962/) +- [Add `std::hash::{DefaultHasher, RandomState}` exports](https://github.com/rust-lang/rust/pull/115694/) +- [Fix rounding issue with exponents in fmt](https://github.com/rust-lang/rust/pull/116301/) +- [Add T: ?Sized to `RwLockReadGuard` and `RwLockWriteGuard`'s Debug impls.](https://github.com/rust-lang/rust/pull/117138/) +- [Windows: Allow `File::create` to work on hidden files](https://github.com/rust-lang/rust/pull/116438/) + + + +Stabilized APIs +--------------- + +- [`Arc::unwrap_or_clone`](https://doc.rust-lang.org/stable/std/sync/struct.Arc.html#method.unwrap_or_clone) +- [`Rc::unwrap_or_clone`](https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.unwrap_or_clone) +- [`Result::inspect`](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.inspect) +- [`Result::inspect_err`](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.inspect_err) +- [`Option::inspect`](https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.inspect) +- [`type_name_of_val`](https://doc.rust-lang.org/stable/std/any/fn.type_name_of_val.html) +- [`std::hash::{DefaultHasher, RandomState}`](https://doc.rust-lang.org/stable/std/hash/index.html#structs) + These were previously available only through `std::collections::hash_map`. +- [`ptr::{from_ref, from_mut}`](https://doc.rust-lang.org/stable/std/ptr/fn.from_ref.html) +- [`ptr::addr_eq`](https://doc.rust-lang.org/stable/std/ptr/fn.addr_eq.html) + + + +Cargo +----- + +See [Cargo release notes](https://github.com/rust-lang/cargo/blob/master/CHANGELOG.md#cargo-176-2024-02-08). + + + +Rustdoc +------- + +- [Don't merge cfg and doc(cfg) attributes for re-exports](https://github.com/rust-lang/rust/pull/113091/) +- [rustdoc: allow resizing the sidebar / hiding the top bar](https://github.com/rust-lang/rust/pull/115660/) +- [rustdoc-search: add support for traits and associated types](https://github.com/rust-lang/rust/pull/116085/) +- [rustdoc: Add highlighting for comments in items declaration](https://github.com/rust-lang/rust/pull/117869/) + + + +Compatibility Notes +------------------- +- [Add allow-by-default lint for unit bindings](https://github.com/rust-lang/rust/pull/112380/) + This is expected to be upgraded to a warning by default in a future Rust + release. Some macros emit bindings with type `()` with user-provided spans, + which means that this lint will warn for user code. +- [Remove x86_64-sun-solaris target.](https://github.com/rust-lang/rust/pull/118091/) +- [Remove asmjs-unknown-emscripten target](https://github.com/rust-lang/rust/pull/117338/) +- [Report errors in jobserver inherited through environment variables](https://github.com/rust-lang/rust/pull/113730/) + This [may warn](https://github.com/rust-lang/rust/issues/120515) on benign problems too. +- [Update the minimum external LLVM to 16.](https://github.com/rust-lang/rust/pull/117947/) +- [Improve `print_tts`](https://github.com/rust-lang/rust/pull/114571/) + This change can break some naive manual parsing of token trees in proc macro + code which expect a particular structure after `.to_string()`, rather than just arbitrary Rust code. +- [Make `IMPLIED_BOUNDS_ENTAILMENT` into a hard error from a lint](https://github.com/rust-lang/rust/pull/117984/) +- [Vec's allocation behavior was changed when collecting some iterators](https://github.com/rust-lang/rust/pull/110353) + Allocation behavior is currently not specified, nevertheless changes can be surprising. + See [`impl FromIterator for Vec`](https://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#impl-FromIterator%3CT%3E-for-Vec%3CT%3E) + for more details. +- [Properly reject `default` on free const items](https://github.com/rust-lang/rust/pull/117818/) + Version 1.75.0 (2023-12-28) ========================== From 4f773af1cc17621e7c52afba6be2db21b2f3aba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sat, 3 Feb 2024 17:34:25 +0100 Subject: [PATCH 28/28] Check for presence of field in typeck results before visiting it Co-authored-by: Michael Goulet --- compiler/rustc_passes/src/dead.rs | 6 +++++- .../field-access-after-const-eval-fail-in-ty.rs | 5 +++++ ...ld-access-after-const-eval-fail-in-ty.stderr | 17 +++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 tests/ui/consts/const-eval/field-access-after-const-eval-fail-in-ty.rs create mode 100644 tests/ui/consts/const-eval/field-access-after-const-eval-fail-in-ty.stderr diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 9be286744351f..d19987cb33cf2 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -464,7 +464,11 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { self.lookup_and_handle_method(expr.hir_id); } hir::ExprKind::Field(ref lhs, ..) => { - self.handle_field_access(lhs, expr.hir_id); + if self.typeck_results().opt_field_index(expr.hir_id).is_some() { + self.handle_field_access(lhs, expr.hir_id); + } else { + self.tcx.dcx().span_delayed_bug(expr.span, "couldn't resolve index for field"); + } } hir::ExprKind::Struct(qpath, fields, _) => { let res = self.typeck_results().qpath_res(qpath, expr.hir_id); diff --git a/tests/ui/consts/const-eval/field-access-after-const-eval-fail-in-ty.rs b/tests/ui/consts/const-eval/field-access-after-const-eval-fail-in-ty.rs new file mode 100644 index 0000000000000..3f1f208459d17 --- /dev/null +++ b/tests/ui/consts/const-eval/field-access-after-const-eval-fail-in-ty.rs @@ -0,0 +1,5 @@ +// Regression test for issue #120615. + +fn main() { + [(); loop {}].field; //~ ERROR constant evaluation is taking a long time +} diff --git a/tests/ui/consts/const-eval/field-access-after-const-eval-fail-in-ty.stderr b/tests/ui/consts/const-eval/field-access-after-const-eval-fail-in-ty.stderr new file mode 100644 index 0000000000000..9d62bbc2187f7 --- /dev/null +++ b/tests/ui/consts/const-eval/field-access-after-const-eval-fail-in-ty.stderr @@ -0,0 +1,17 @@ +error: constant evaluation is taking a long time + --> $DIR/field-access-after-const-eval-fail-in-ty.rs:4:10 + | +LL | [(); loop {}].field; + | ^^^^^^^ + | + = note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval. + If your compilation actually takes a long time, you can safely allow the lint. +help: the constant being evaluated + --> $DIR/field-access-after-const-eval-fail-in-ty.rs:4:10 + | +LL | [(); loop {}].field; + | ^^^^^^^ + = note: `#[deny(long_running_const_eval)]` on by default + +error: aborting due to 1 previous error +