From 26c4893ae6a6bd5d611fd6c7b3c803a720138d40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Bj=C3=B8rnager=20Jensen?= Date: Tue, 24 Sep 2024 22:40:29 +0200 Subject: [PATCH 01/16] Mark 'get_mut' and 'set_position' in 'std::io::Cursor' as const; --- library/std/src/io/cursor.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index 9f913eae095..fbfdb4fa023 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -153,7 +153,8 @@ impl Cursor { /// let reference = buff.get_mut(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self) -> &mut T { + #[rustc_const_unstable(feature = "const_mut_cursor", issue = "130801")] + pub const fn get_mut(&mut self) -> &mut T { &mut self.inner } @@ -200,7 +201,8 @@ impl Cursor { /// assert_eq!(buff.position(), 4); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn set_position(&mut self, pos: u64) { + #[rustc_const_unstable(feature = "const_mut_cursor", issue = "130801")] + pub const fn set_position(&mut self, pos: u64) { self.pos = pos; } } From 3727a8c4d8169043a40f327dbd39db0c4448aef6 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Sun, 1 Sep 2024 04:20:20 +0530 Subject: [PATCH 02/16] uefi: process: Add args support - Wrap all args with quotes. - Escape ^ and " inside quotes using ^. Signed-off-by: Ayush Singh --- library/std/src/sys/pal/uefi/process.rs | 68 ++++++++++++++++++++----- 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs index fdc5f5d7e4f..4494b3df57b 100644 --- a/library/std/src/sys/pal/uefi/process.rs +++ b/library/std/src/sys/pal/uefi/process.rs @@ -18,6 +18,7 @@ use crate::{fmt, io}; #[derive(Debug)] pub struct Command { prog: OsString, + args: Vec, stdout: Option, stderr: Option, } @@ -39,12 +40,11 @@ pub enum Stdio { impl Command { pub fn new(program: &OsStr) -> Command { - Command { prog: program.to_os_string(), stdout: None, stderr: None } + Command { prog: program.to_os_string(), args: Vec::new(), stdout: None, stderr: None } } - // FIXME: Implement arguments as reverse of parsing algorithm - pub fn arg(&mut self, _arg: &OsStr) { - panic!("unsupported") + pub fn arg(&mut self, arg: &OsStr) { + self.args.push(arg.to_os_string()); } pub fn env_mut(&mut self) -> &mut CommandEnv { @@ -72,7 +72,7 @@ impl Command { } pub fn get_args(&self) -> CommandArgs<'_> { - panic!("unsupported") + CommandArgs { iter: self.args.iter() } } pub fn get_envs(&self) -> CommandEnvs<'_> { @@ -116,6 +116,12 @@ impl Command { pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?; + // UEFI adds the bin name by default + if !self.args.is_empty() { + let args = uefi_command_internal::create_args(&self.prog, &self.args); + cmd.set_args(args); + } + // Setup Stdout let stdout = self.stdout.unwrap_or(Stdio::MakePipe); let stdout = Self::create_pipe(stdout)?; @@ -315,7 +321,7 @@ mod uefi_command_internal { stdout: Option>, stderr: Option>, st: OwnedTable, - args: Option>, + args: Option<(*mut u16, usize)>, } impl Image { @@ -449,20 +455,20 @@ mod uefi_command_internal { } } - pub fn set_args(&mut self, args: &OsStr) { + pub fn set_args(&mut self, args: Box<[u16]>) { let loaded_image: NonNull = helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap(); - let mut args = args.encode_wide().collect::>(); - let args_size = (crate::mem::size_of::() * args.len()) as u32; + let len = args.len(); + let args_size: u32 = crate::mem::size_of_val(&args).try_into().unwrap(); + let ptr = Box::into_raw(args).as_mut_ptr(); unsafe { - (*loaded_image.as_ptr()).load_options = - args.as_mut_ptr() as *mut crate::ffi::c_void; + (*loaded_image.as_ptr()).load_options = ptr as *mut crate::ffi::c_void; (*loaded_image.as_ptr()).load_options_size = args_size; } - self.args = Some(args); + self.args = Some((ptr, len)); } fn update_st_crc32(&mut self) -> io::Result<()> { @@ -502,6 +508,10 @@ mod uefi_command_internal { ((*bt.as_ptr()).unload_image)(self.handle.as_ptr()); } } + + if let Some((ptr, len)) = self.args { + let _ = unsafe { Box::from_raw(crate::ptr::slice_from_raw_parts_mut(ptr, len)) }; + } } } @@ -681,4 +691,38 @@ mod uefi_command_internal { } } } + + pub fn create_args(prog: &OsStr, args: &[OsString]) -> Box<[u16]> { + const QUOTE: u16 = 0x0022; + const SPACE: u16 = 0x0020; + const CARET: u16 = 0x005e; + const NULL: u16 = 0; + + // This is the lower bound on the final length under the assumption that + // the arguments only contain ASCII characters. + let mut res = Vec::with_capacity(args.iter().map(|arg| arg.len() + 3).sum()); + + // Wrap program name in quotes to avoid any problems + res.push(QUOTE); + res.extend(prog.encode_wide()); + res.push(QUOTE); + res.push(SPACE); + + for arg in args { + // Wrap the argument in quotes to be treat as single arg + res.push(QUOTE); + for c in arg.encode_wide() { + // CARET in quotes is used to escape CARET or QUOTE + if c == QUOTE || c == CARET { + res.push(CARET); + } + res.push(c); + } + res.push(QUOTE); + + res.push(SPACE); + } + + res.into_boxed_slice() + } } From ff2f7a7a834843ea74b1e7d6511eb4ad06f43981 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 6 Nov 2024 19:46:54 +0000 Subject: [PATCH 03/16] Point at `const` definition when used instead of a binding in a `let` statement After: ``` error[E0005]: refutable pattern in local binding --> $DIR/bad-pattern.rs:19:13 | LL | const PAT: u32 = 0; | -------------- missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable ... LL | let PAT = v1; | ^^^ | | | pattern `1_u32..=u32::MAX` not covered | help: introduce a variable instead: `PAT_var` | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `u32` ``` Before: ``` error[E0005]: refutable pattern in local binding --> $DIR/bad-pattern.rs:19:13 | LL | let PAT = v1; | ^^^ | | | pattern `1_u32..=u32::MAX` not covered | missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable | help: introduce a variable instead: `PAT_var` | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `u32` ``` --- compiler/rustc_middle/src/thir.rs | 11 +++++++++-- compiler/rustc_middle/src/thir/visit.rs | 2 +- .../src/build/custom/parse/instruction.rs | 4 +++- .../src/build/matches/match_pair.rs | 4 +++- .../rustc_mir_build/src/build/matches/mod.rs | 1 + compiler/rustc_mir_build/src/check_unsafety.rs | 1 + compiler/rustc_mir_build/src/errors.rs | 5 +++-- .../src/thir/pattern/check_match.rs | 18 ++++++++++++++++-- .../rustc_mir_build/src/thir/pattern/mod.rs | 12 ++++++++++-- compiler/rustc_mir_build/src/thir/print.rs | 2 +- compiler/rustc_pattern_analysis/src/rustc.rs | 2 +- compiler/rustc_ty_utils/src/consts.rs | 4 +++- .../2229_closure_analysis/bad-pattern.stderr | 4 +++- tests/ui/consts/const-pattern-irrefutable.rs | 6 +++--- .../ui/consts/const-pattern-irrefutable.stderr | 18 ++++++++++++------ tests/ui/mir/issue-112269.stderr | 6 ++++-- .../const-pat-non-exaustive-let-new-var.rs | 2 +- .../const-pat-non-exaustive-let-new-var.stderr | 4 +++- 18 files changed, 78 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 45ceb0a555d..821f8c99704 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -640,6 +640,7 @@ impl<'tcx> Pat<'tcx> { | Range(..) | Binding { subpattern: None, .. } | Constant { .. } + | NamedConstant { .. } | Error(_) => {} AscribeUserType { subpattern, .. } | Binding { subpattern: Some(subpattern), .. } @@ -788,6 +789,12 @@ pub enum PatKind<'tcx> { value: mir::Const<'tcx>, }, + /// Same as `Constant`, but that came from a `const` that we can point at in diagnostics. + NamedConstant { + value: mir::Const<'tcx>, + span: Span, + }, + /// Inline constant found while lowering a pattern. InlineConstant { /// [LocalDefId] of the constant, we need this so that we have a @@ -1084,8 +1091,8 @@ mod size_asserts { static_assert_size!(Block, 48); static_assert_size!(Expr<'_>, 64); static_assert_size!(ExprKind<'_>, 40); - static_assert_size!(Pat<'_>, 64); - static_assert_size!(PatKind<'_>, 48); + static_assert_size!(Pat<'_>, 72); + static_assert_size!(PatKind<'_>, 56); static_assert_size!(Stmt<'_>, 48); static_assert_size!(StmtKind<'_>, 48); // tidy-alphabetical-end diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 36f0e3d890c..759ed77dbcb 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -246,7 +246,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( visitor.visit_pat(&subpattern.pattern); } } - Constant { value: _ } => {} + Constant { value: _ } | NamedConstant { value: _, span: _ } => {} InlineConstant { def: _, subpattern } => visitor.visit_pat(subpattern), Range(_) => {} Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => { diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 07964e304b9..049586fd6a0 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -144,7 +144,9 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { let mut targets = Vec::new(); for arm in rest { let arm = &self.thir[*arm]; - let PatKind::Constant { value } = arm.pattern.kind else { + let (PatKind::Constant { value } | PatKind::NamedConstant { value, span: _ }) = + arm.pattern.kind + else { return Err(ParseError { span: arm.pattern.span, item_description: format!("{:?}", arm.pattern.kind), diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs index 6df50057ee8..83a1e021484 100644 --- a/compiler/rustc_mir_build/src/build/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs @@ -129,7 +129,9 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> { } } - PatKind::Constant { value } => TestCase::Constant { value }, + PatKind::Constant { value } | PatKind::NamedConstant { value, span: _ } => { + TestCase::Constant { value } + } PatKind::AscribeUserType { ascription: thir::Ascription { ref annotation, variance }, diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index a62d4e9d873..ac5be665654 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -882,6 +882,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } PatKind::Constant { .. } + | PatKind::NamedConstant { .. } | PatKind::Range { .. } | PatKind::Wild | PatKind::Never diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 33e194fa246..d073cbdd877 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -316,6 +316,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { PatKind::Binding { .. } // match is conditional on having this value | PatKind::Constant { .. } + | PatKind::NamedConstant { .. } | PatKind::Variant { .. } | PatKind::Leaf { .. } | PatKind::Deref { .. } diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 00f65e0c7d0..04eb7ffe776 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -860,8 +860,10 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> { pub(crate) uncovered: Uncovered, #[subdiagnostic] pub(crate) inform: Option, + #[label(mir_build_confused)] + pub(crate) interpreted_as_const: Option, #[subdiagnostic] - pub(crate) interpreted_as_const: Option, + pub(crate) interpreted_as_const_sugg: Option, #[subdiagnostic] pub(crate) adt_defined_here: Option>, #[note(mir_build_privately_uninhabited)] @@ -913,7 +915,6 @@ impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> { code = "{variable}_var", applicability = "maybe-incorrect" )] -#[label(mir_build_confused)] pub(crate) struct InterpretedAsConst { #[primary_span] pub(crate) span: Span, diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index f222a869c03..b54e1c2b552 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -668,8 +668,20 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { let mut let_suggestion = None; let mut misc_suggestion = None; let mut interpreted_as_const = None; + let mut interpreted_as_const_sugg = None; - if let PatKind::Constant { .. } + if let PatKind::NamedConstant { span, .. } + | PatKind::AscribeUserType { + subpattern: box Pat { kind: PatKind::NamedConstant { span, .. }, .. }, + .. + } = pat.kind + && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span) + { + // When we encounter a constant as the binding name, point at the `const` definition. + interpreted_as_const = Some(span); + interpreted_as_const_sugg = + Some(InterpretedAsConst { span: pat.span, variable: snippet }); + } else if let PatKind::Constant { .. } | PatKind::AscribeUserType { subpattern: box Pat { kind: PatKind::Constant { .. }, .. }, .. @@ -683,7 +695,8 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { start_span: pat.span.shrink_to_lo(), }); } else if snippet.chars().all(|c| c.is_alphanumeric() || c == '_') { - interpreted_as_const = + interpreted_as_const = Some(pat.span); + interpreted_as_const_sugg = Some(InterpretedAsConst { span: pat.span, variable: snippet }); } } @@ -733,6 +746,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { uncovered: Uncovered::new(pat.span, &cx, witnesses), inform, interpreted_as_const, + interpreted_as_const_sugg, witness_1_is_privately_uninhabited, _p: (), pattern_ty, diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index ec852add94d..260ace55fba 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -157,7 +157,9 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } kind => (kind, None, None), }; - let value = if let PatKind::Constant { value } = kind { + let value = if let PatKind::Constant { value } + | PatKind::NamedConstant { value, span: _ } = kind + { value } else { let msg = format!( @@ -560,9 +562,15 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { _ => return pat_from_kind(self.lower_variant_or_leaf(res, id, span, ty, vec![])), }; + // HERE let args = self.typeck_results.node_args(id); let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args }); - let pattern = self.const_to_pat(c, ty, id, span); + let def_span = self.tcx.def_span(def_id); + let mut pattern = self.const_to_pat(c, ty, id, span); + if let PatKind::Constant { value } = pattern.kind { + pattern.kind = PatKind::NamedConstant { value, span: def_span }; + } + tracing::info!("pattern {pattern:#?} {c:?} {ty:?} {id:?}"); if !is_associated_const { return pattern; diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index dae13df4054..3fe75439339 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -702,7 +702,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_pat(subpattern, depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } - PatKind::Constant { value } => { + PatKind::Constant { value } | PatKind::NamedConstant { value, span: _ } => { print_indented!(self, "Constant {", depth_lvl + 1); print_indented!(self, format!("value: {:?}", value), depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 9ea5023064c..6496d9fd73d 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -536,7 +536,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { ), } } - PatKind::Constant { value } => { + PatKind::Constant { value } | PatKind::NamedConstant { value, span: _ } => { match ty.kind() { ty::Bool => { ctor = match value.try_eval_bool(cx.tcx, cx.param_env) { diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 637e239a570..3a0eb8143cd 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -370,7 +370,9 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> { } match pat.kind { - thir::PatKind::Constant { value } => value.has_non_region_param(), + thir::PatKind::Constant { value } | thir::PatKind::NamedConstant { value, span: _ } => { + value.has_non_region_param() + } thir::PatKind::Range(box thir::PatRange { lo, hi, .. }) => { lo.has_non_region_param() || hi.has_non_region_param() } diff --git a/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr b/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr index ca8c2a16d32..5692d530b06 100644 --- a/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr +++ b/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr @@ -97,11 +97,13 @@ LL | if let Refutable::A = v3 { todo!() }; error[E0005]: refutable pattern in local binding --> $DIR/bad-pattern.rs:19:13 | +LL | const PAT: u32 = 0; + | -------------- missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable +... LL | let PAT = v1; | ^^^ | | | pattern `1_u32..=u32::MAX` not covered - | missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable | help: introduce a variable instead: `PAT_var` | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant diff --git a/tests/ui/consts/const-pattern-irrefutable.rs b/tests/ui/consts/const-pattern-irrefutable.rs index 61bdf57ffdb..54d2ad32386 100644 --- a/tests/ui/consts/const-pattern-irrefutable.rs +++ b/tests/ui/consts/const-pattern-irrefutable.rs @@ -1,28 +1,28 @@ mod foo { pub const b: u8 = 2; + //~^ missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable pub const d: u8 = 2; + //~^ missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable } use foo::b as c; use foo::d; const a: u8 = 2; +//~^ missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable fn main() { let a = 4; //~^ ERROR refutable pattern in local binding //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - //~| missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable //~| HELP introduce a variable instead let c = 4; //~^ ERROR refutable pattern in local binding //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - //~| missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable //~| HELP introduce a variable instead let d = 4; //~^ ERROR refutable pattern in local binding //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - //~| missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable //~| HELP introduce a variable instead fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115). } diff --git a/tests/ui/consts/const-pattern-irrefutable.stderr b/tests/ui/consts/const-pattern-irrefutable.stderr index 2aed68bdd64..d4365fa16e8 100644 --- a/tests/ui/consts/const-pattern-irrefutable.stderr +++ b/tests/ui/consts/const-pattern-irrefutable.stderr @@ -1,11 +1,13 @@ error[E0005]: refutable pattern in local binding - --> $DIR/const-pattern-irrefutable.rs:12:9 + --> $DIR/const-pattern-irrefutable.rs:15:9 | +LL | const a: u8 = 2; + | ----------- missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable +... LL | let a = 4; | ^ | | | patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - | missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable | help: introduce a variable instead: `a_var` | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant @@ -13,13 +15,15 @@ LL | let a = 4; = note: the matched value is of type `u8` error[E0005]: refutable pattern in local binding - --> $DIR/const-pattern-irrefutable.rs:17:9 + --> $DIR/const-pattern-irrefutable.rs:19:9 | +LL | pub const b: u8 = 2; + | --------------- missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable +... LL | let c = 4; | ^ | | | patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - | missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable | help: introduce a variable instead: `c_var` | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant @@ -27,13 +31,15 @@ LL | let c = 4; = note: the matched value is of type `u8` error[E0005]: refutable pattern in local binding - --> $DIR/const-pattern-irrefutable.rs:22:9 + --> $DIR/const-pattern-irrefutable.rs:23:9 | +LL | pub const d: u8 = 2; + | --------------- missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable +... LL | let d = 4; | ^ | | | patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - | missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable | help: introduce a variable instead: `d_var` | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant diff --git a/tests/ui/mir/issue-112269.stderr b/tests/ui/mir/issue-112269.stderr index f5b79602797..945a7e25dd0 100644 --- a/tests/ui/mir/issue-112269.stderr +++ b/tests/ui/mir/issue-112269.stderr @@ -1,11 +1,12 @@ error[E0005]: refutable pattern in local binding --> $DIR/issue-112269.rs:3:9 | +LL | const x: i32 = 4; + | ------------ missing patterns are not covered because `x` is interpreted as a constant pattern, not a new variable LL | let x: i32 = 3; | ^ | | | patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered - | missing patterns are not covered because `x` is interpreted as a constant pattern, not a new variable | help: introduce a variable instead: `x_var` | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant @@ -15,11 +16,12 @@ LL | let x: i32 = 3; error[E0005]: refutable pattern in local binding --> $DIR/issue-112269.rs:7:9 | +LL | const y: i32 = 3; + | ------------ missing patterns are not covered because `y` is interpreted as a constant pattern, not a new variable LL | let y = 4; | ^ | | | patterns `i32::MIN..=2_i32` and `4_i32..=i32::MAX` not covered - | missing patterns are not covered because `y` is interpreted as a constant pattern, not a new variable | help: introduce a variable instead: `y_var` | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant diff --git a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs index af47ba8baa3..1a440a90cd7 100644 --- a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs +++ b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs @@ -2,9 +2,9 @@ fn main() { let A = 3; //~^ ERROR refutable pattern in local binding //~| patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered - //~| missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable //~| HELP introduce a variable instead //~| SUGGESTION A_var const A: i32 = 2; + //~^ missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable } diff --git a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr index b6c28612802..29c4b2905eb 100644 --- a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr +++ b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr @@ -5,8 +5,10 @@ LL | let A = 3; | ^ | | | patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered - | missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable | help: introduce a variable instead: `A_var` +... +LL | const A: i32 = 2; + | ------------ missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html From c25b44bee96e4489dab8f44409ba347bfeb328b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 6 Nov 2024 21:10:31 +0000 Subject: [PATCH 04/16] Fold `PatKind::NamedConstant` into `PatKind::Constant` --- compiler/rustc_middle/src/thir.rs | 9 ++------- compiler/rustc_middle/src/thir/visit.rs | 2 +- .../src/build/custom/parse/instruction.rs | 4 +--- .../rustc_mir_build/src/build/matches/match_pair.rs | 4 +--- compiler/rustc_mir_build/src/build/matches/mod.rs | 1 - compiler/rustc_mir_build/src/check_unsafety.rs | 1 - .../rustc_mir_build/src/thir/pattern/check_match.rs | 5 +++-- .../src/thir/pattern/const_to_pat.rs | 7 ++++++- compiler/rustc_mir_build/src/thir/pattern/mod.rs | 13 ++++--------- compiler/rustc_mir_build/src/thir/print.rs | 2 +- compiler/rustc_pattern_analysis/src/rustc.rs | 2 +- compiler/rustc_ty_utils/src/consts.rs | 4 +--- 12 files changed, 21 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 821f8c99704..84f5f3a4611 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -640,7 +640,6 @@ impl<'tcx> Pat<'tcx> { | Range(..) | Binding { subpattern: None, .. } | Constant { .. } - | NamedConstant { .. } | Error(_) => {} AscribeUserType { subpattern, .. } | Binding { subpattern: Some(subpattern), .. } @@ -787,12 +786,8 @@ pub enum PatKind<'tcx> { /// * `String`, if `string_deref_patterns` is enabled. Constant { value: mir::Const<'tcx>, - }, - - /// Same as `Constant`, but that came from a `const` that we can point at in diagnostics. - NamedConstant { - value: mir::Const<'tcx>, - span: Span, + /// The `const` item this constant came from, if any. + opt_def: Option, }, /// Inline constant found while lowering a pattern. diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 759ed77dbcb..92c0add65ba 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -246,7 +246,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( visitor.visit_pat(&subpattern.pattern); } } - Constant { value: _ } | NamedConstant { value: _, span: _ } => {} + Constant { value: _, opt_def: _ } => {} InlineConstant { def: _, subpattern } => visitor.visit_pat(subpattern), Range(_) => {} Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => { diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 049586fd6a0..60624855fea 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -144,9 +144,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { let mut targets = Vec::new(); for arm in rest { let arm = &self.thir[*arm]; - let (PatKind::Constant { value } | PatKind::NamedConstant { value, span: _ }) = - arm.pattern.kind - else { + let PatKind::Constant { value, opt_def: _ } = arm.pattern.kind else { return Err(ParseError { span: arm.pattern.span, item_description: format!("{:?}", arm.pattern.kind), diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs index 83a1e021484..df3cf53eb17 100644 --- a/compiler/rustc_mir_build/src/build/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs @@ -129,9 +129,7 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> { } } - PatKind::Constant { value } | PatKind::NamedConstant { value, span: _ } => { - TestCase::Constant { value } - } + PatKind::Constant { value, opt_def: _ } => TestCase::Constant { value }, PatKind::AscribeUserType { ascription: thir::Ascription { ref annotation, variance }, diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index ac5be665654..a62d4e9d873 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -882,7 +882,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } PatKind::Constant { .. } - | PatKind::NamedConstant { .. } | PatKind::Range { .. } | PatKind::Wild | PatKind::Never diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index d073cbdd877..33e194fa246 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -316,7 +316,6 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { PatKind::Binding { .. } // match is conditional on having this value | PatKind::Constant { .. } - | PatKind::NamedConstant { .. } | PatKind::Variant { .. } | PatKind::Leaf { .. } | PatKind::Deref { .. } diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index b54e1c2b552..f3cfc8b1a22 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -670,13 +670,14 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { let mut interpreted_as_const = None; let mut interpreted_as_const_sugg = None; - if let PatKind::NamedConstant { span, .. } + if let PatKind::Constant { opt_def: Some(def_id), .. } | PatKind::AscribeUserType { - subpattern: box Pat { kind: PatKind::NamedConstant { span, .. }, .. }, + subpattern: box Pat { kind: PatKind::Constant { opt_def: Some(def_id), .. }, .. }, .. } = pat.kind && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span) { + let span = self.tcx.def_span(def_id); // When we encounter a constant as the binding name, point at the `const` definition. interpreted_as_const = Some(span); interpreted_as_const_sugg = diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 82632350af5..06b13274efc 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -266,6 +266,7 @@ impl<'tcx> ConstToPat<'tcx> { // optimization for now. ty::Str => PatKind::Constant { value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)), + opt_def: None, }, // All other references are converted into deref patterns and then recursively // convert the dereferenced constant to a pattern that is the sub-pattern of the @@ -311,13 +312,17 @@ impl<'tcx> ConstToPat<'tcx> { } else { PatKind::Constant { value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)), + opt_def: None, } } } ty::Pat(..) | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => { // The raw pointers we see here have been "vetted" by valtree construction to be // just integers, so we simply allow them. - PatKind::Constant { value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)) } + PatKind::Constant { + value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)), + opt_def: None, + } } ty::FnPtr(..) => { unreachable!( diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 260ace55fba..11d06e5a1cc 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -157,9 +157,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } kind => (kind, None, None), }; - let value = if let PatKind::Constant { value } - | PatKind::NamedConstant { value, span: _ } = kind - { + let value = if let PatKind::Constant { value, opt_def: _ } = kind { value } else { let msg = format!( @@ -253,7 +251,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { (RangeEnd::Included, Some(Ordering::Less)) => {} // `x..=y` where `x == y` and `x` and `y` are finite. (RangeEnd::Included, Some(Ordering::Equal)) if lo.is_finite() && hi.is_finite() => { - kind = PatKind::Constant { value: lo.as_finite().unwrap() }; + kind = PatKind::Constant { value: lo.as_finite().unwrap(), opt_def: None }; } // `..=x` where `x == ty::MIN`. (RangeEnd::Included, Some(Ordering::Equal)) if !lo.is_finite() => {} @@ -562,15 +560,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { _ => return pat_from_kind(self.lower_variant_or_leaf(res, id, span, ty, vec![])), }; - // HERE let args = self.typeck_results.node_args(id); let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args }); - let def_span = self.tcx.def_span(def_id); let mut pattern = self.const_to_pat(c, ty, id, span); - if let PatKind::Constant { value } = pattern.kind { - pattern.kind = PatKind::NamedConstant { value, span: def_span }; + if let PatKind::Constant { value, opt_def: None } = pattern.kind { + pattern.kind = PatKind::Constant { value, opt_def: Some(def_id) }; } - tracing::info!("pattern {pattern:#?} {c:?} {ty:?} {id:?}"); if !is_associated_const { return pattern; diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 3fe75439339..43bca812bbd 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -702,7 +702,7 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_pat(subpattern, depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } - PatKind::Constant { value } | PatKind::NamedConstant { value, span: _ } => { + PatKind::Constant { value, opt_def: _ } => { print_indented!(self, "Constant {", depth_lvl + 1); print_indented!(self, format!("value: {:?}", value), depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 6496d9fd73d..ec671150c40 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -536,7 +536,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { ), } } - PatKind::Constant { value } | PatKind::NamedConstant { value, span: _ } => { + PatKind::Constant { value, opt_def: _ } => { match ty.kind() { ty::Bool => { ctor = match value.try_eval_bool(cx.tcx, cx.param_env) { diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 3a0eb8143cd..12f169d718c 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -370,9 +370,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> { } match pat.kind { - thir::PatKind::Constant { value } | thir::PatKind::NamedConstant { value, span: _ } => { - value.has_non_region_param() - } + thir::PatKind::Constant { value, opt_def: _ } => value.has_non_region_param(), thir::PatKind::Range(box thir::PatRange { lo, hi, .. }) => { lo.has_non_region_param() || hi.has_non_region_param() } From 6dc79f6133d24100cecbcb24e256b9f149d2b47a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 6 Nov 2024 21:28:26 +0000 Subject: [PATCH 05/16] Use `item_name` instead of a span snippet when talking about const pattern --- compiler/rustc_mir_build/src/thir/pattern/check_match.rs | 5 ++--- tests/ui/consts/const-pattern-irrefutable.rs | 2 +- tests/ui/consts/const-pattern-irrefutable.stderr | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index f3cfc8b1a22..a8830b346ae 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -675,13 +675,12 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { subpattern: box Pat { kind: PatKind::Constant { opt_def: Some(def_id), .. }, .. }, .. } = pat.kind - && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span) { let span = self.tcx.def_span(def_id); + let variable = self.tcx.item_name(def_id).to_string(); // When we encounter a constant as the binding name, point at the `const` definition. interpreted_as_const = Some(span); - interpreted_as_const_sugg = - Some(InterpretedAsConst { span: pat.span, variable: snippet }); + interpreted_as_const_sugg = Some(InterpretedAsConst { span: pat.span, variable }); } else if let PatKind::Constant { .. } | PatKind::AscribeUserType { subpattern: box Pat { kind: PatKind::Constant { .. }, .. }, diff --git a/tests/ui/consts/const-pattern-irrefutable.rs b/tests/ui/consts/const-pattern-irrefutable.rs index 54d2ad32386..c590ec8fcd3 100644 --- a/tests/ui/consts/const-pattern-irrefutable.rs +++ b/tests/ui/consts/const-pattern-irrefutable.rs @@ -1,6 +1,6 @@ mod foo { pub const b: u8 = 2; - //~^ missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable + //~^ missing patterns are not covered because `b` is interpreted as a constant pattern, not a new variable pub const d: u8 = 2; //~^ missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable } diff --git a/tests/ui/consts/const-pattern-irrefutable.stderr b/tests/ui/consts/const-pattern-irrefutable.stderr index d4365fa16e8..c118ce9e48f 100644 --- a/tests/ui/consts/const-pattern-irrefutable.stderr +++ b/tests/ui/consts/const-pattern-irrefutable.stderr @@ -18,13 +18,13 @@ error[E0005]: refutable pattern in local binding --> $DIR/const-pattern-irrefutable.rs:19:9 | LL | pub const b: u8 = 2; - | --------------- missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable + | --------------- missing patterns are not covered because `b` is interpreted as a constant pattern, not a new variable ... LL | let c = 4; | ^ | | | patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - | help: introduce a variable instead: `c_var` + | help: introduce a variable instead: `b_var` | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html From a5b4d458a12218b2bbbcb42887d1fe1468f1986e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 7 Nov 2024 18:34:40 +0000 Subject: [PATCH 06/16] Point at const when intended binding fall-through pattern is a const ``` error[E0004]: non-exhaustive patterns: `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered --> $DIR/intended-binding-pattern-is-const.rs:2:11 | LL | match 1 { | ^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered LL | x => {} | - this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `x` | = note: the matched value is of type `i32` note: constant `x` defined here --> $DIR/intended-binding-pattern-is-const.rs:7:5 | LL | const x: i32 = 4; | ^^^^^^^^^^^^ help: if you meant to introduce a binding, use a different name | LL | x_var => {} | ++++ help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL | x => {}, i32::MIN..=3_i32 | 5_i32..=i32::MAX => todo!() | ++++++++++++++++++++++++++++++++++++++++++++++++ ``` --- .../src/thir/pattern/check_match.rs | 29 ++++++++++++++++--- .../intended-binding-pattern-is-const.rs | 10 +++++++ .../intended-binding-pattern-is-const.stderr | 27 +++++++++++++++++ 3 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 tests/ui/match/intended-binding-pattern-is-const.rs create mode 100644 tests/ui/match/intended-binding-pattern-is-const.stderr diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index a8830b346ae..edd51b521fa 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1116,13 +1116,13 @@ fn report_non_exhaustive_match<'p, 'tcx>( if ty.is_ptr_sized_integral() { if ty.inner() == cx.tcx.types.usize { err.note(format!( - "`{ty}` does not have a fixed maximum value, so half-open ranges are necessary to match \ - exhaustively", + "`{ty}` does not have a fixed maximum value, so half-open ranges are \ + necessary to match exhaustively", )); } else if ty.inner() == cx.tcx.types.isize { err.note(format!( - "`{ty}` does not have fixed minimum and maximum values, so half-open ranges are necessary to match \ - exhaustively", + "`{ty}` does not have fixed minimum and maximum values, so half-open \ + ranges are necessary to match exhaustively", )); } } else if ty.inner() == cx.tcx.types.str_ { @@ -1143,6 +1143,27 @@ fn report_non_exhaustive_match<'p, 'tcx>( } } + for &arm in arms { + let arm = &thir.arms[arm]; + if let PatKind::Constant { opt_def: Some(def_id), .. } = arm.pattern.kind { + let const_name = cx.tcx.item_name(def_id); + err.span_label( + arm.pattern.span, + format!( + "this pattern doesn't introduce a new catch-all binding, but rather pattern \ + matches against the value of constant `{const_name}`", + ), + ); + err.span_note(cx.tcx.def_span(def_id), format!("constant `{const_name}` defined here")); + err.span_suggestion_verbose( + arm.pattern.span.shrink_to_hi(), + "if you meant to introduce a binding, use a different name", + "_var".to_string(), + Applicability::MaybeIncorrect, + ); + } + } + // Whether we suggest the actual missing patterns or `_`. let suggest_the_witnesses = witnesses.len() < 4; let suggested_arm = if suggest_the_witnesses { diff --git a/tests/ui/match/intended-binding-pattern-is-const.rs b/tests/ui/match/intended-binding-pattern-is-const.rs new file mode 100644 index 00000000000..95c8119cdb9 --- /dev/null +++ b/tests/ui/match/intended-binding-pattern-is-const.rs @@ -0,0 +1,10 @@ +fn main() { + match 1 { //~ ERROR non-exhaustive patterns + //~^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered + //~| the matched value is of type `i32` + x => {} //~ this pattern doesn't introduce a new catch-all binding + //~^ HELP ensure that all possible cases are being handled + //~| HELP if you meant to introduce a binding, use a different name + } + const x: i32 = 4; //~ NOTE constant `x` defined here +} diff --git a/tests/ui/match/intended-binding-pattern-is-const.stderr b/tests/ui/match/intended-binding-pattern-is-const.stderr new file mode 100644 index 00000000000..99af1c7a16e --- /dev/null +++ b/tests/ui/match/intended-binding-pattern-is-const.stderr @@ -0,0 +1,27 @@ +error[E0004]: non-exhaustive patterns: `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered + --> $DIR/intended-binding-pattern-is-const.rs:2:11 + | +LL | match 1 { + | ^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered +... +LL | x => {} + | - this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `x` + | + = note: the matched value is of type `i32` +note: constant `x` defined here + --> $DIR/intended-binding-pattern-is-const.rs:9:5 + | +LL | const x: i32 = 4; + | ^^^^^^^^^^^^ +help: if you meant to introduce a binding, use a different name + | +LL | x_var => {} + | ++++ +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL | x => {}, i32::MIN..=3_i32 | 5_i32..=i32::MAX => todo!() + | ++++++++++++++++++++++++++++++++++++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0004`. From f563efec156319d726095a82ea3d0f167c7edac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 7 Nov 2024 19:34:23 +0000 Subject: [PATCH 07/16] Unify expanded constants and named constants in `PatKind` --- compiler/rustc_middle/src/thir.rs | 22 +++--- compiler/rustc_middle/src/thir/visit.rs | 4 +- .../src/build/custom/parse/instruction.rs | 2 +- .../src/build/matches/match_pair.rs | 10 ++- .../rustc_mir_build/src/build/matches/mod.rs | 2 +- .../rustc_mir_build/src/check_unsafety.rs | 10 ++- .../src/thir/pattern/check_match.rs | 8 ++- .../src/thir/pattern/const_to_pat.rs | 7 +- .../rustc_mir_build/src/thir/pattern/mod.rs | 37 +++++++--- compiler/rustc_mir_build/src/thir/print.rs | 9 +-- compiler/rustc_pattern_analysis/src/rustc.rs | 4 +- compiler/rustc_ty_utils/src/consts.rs | 2 +- tests/ui/consts/const-pattern-irrefutable.rs | 21 +++++- .../consts/const-pattern-irrefutable.stderr | 39 +++++++--- .../const_in_pattern/incomplete-slice.stderr | 12 ++++ .../usefulness/match-arm-statics-2.stderr | 12 ++++ .../slice-patterns-exhaustiveness.stderr | 72 +++++++++++++++++++ 17 files changed, 215 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 84f5f3a4611..f37c8486df5 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -645,7 +645,7 @@ impl<'tcx> Pat<'tcx> { | Binding { subpattern: Some(subpattern), .. } | Deref { subpattern } | DerefPattern { subpattern, .. } - | InlineConstant { subpattern, .. } => subpattern.walk_(it), + | ExpandedConstant { subpattern, .. } => subpattern.walk_(it), Leaf { subpatterns } | Variant { subpatterns, .. } => { subpatterns.iter().for_each(|field| field.pattern.walk_(it)) } @@ -786,16 +786,18 @@ pub enum PatKind<'tcx> { /// * `String`, if `string_deref_patterns` is enabled. Constant { value: mir::Const<'tcx>, - /// The `const` item this constant came from, if any. - opt_def: Option, }, - /// Inline constant found while lowering a pattern. - InlineConstant { - /// [LocalDefId] of the constant, we need this so that we have a + /// Inline or named constant found while lowering a pattern. + ExpandedConstant { + /// [DefId] of the constant, we need this so that we have a /// reference that can be used by unsafety checking to visit nested - /// unevaluated constants. - def: LocalDefId, + /// unevaluated constants. If the `DefId` doesn't correspond to a local + /// crate, it points at the `const` item. + def_id: DefId, + /// If `false`, then `def_id` points at a `const` item, otherwise it + /// corresponds to a local inline const. + is_inline: bool, /// If the inline constant is used in a range pattern, this subpattern /// represents the range (if both ends are inline constants, there will /// be multiple InlineConstant wrappers). @@ -1086,8 +1088,8 @@ mod size_asserts { static_assert_size!(Block, 48); static_assert_size!(Expr<'_>, 64); static_assert_size!(ExprKind<'_>, 40); - static_assert_size!(Pat<'_>, 72); - static_assert_size!(PatKind<'_>, 56); + static_assert_size!(Pat<'_>, 64); + static_assert_size!(PatKind<'_>, 48); static_assert_size!(Stmt<'_>, 48); static_assert_size!(StmtKind<'_>, 48); // tidy-alphabetical-end diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 92c0add65ba..81202a6eaad 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -246,8 +246,8 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( visitor.visit_pat(&subpattern.pattern); } } - Constant { value: _, opt_def: _ } => {} - InlineConstant { def: _, subpattern } => visitor.visit_pat(subpattern), + Constant { value: _ } => {} + ExpandedConstant { def_id: _, is_inline: _, subpattern } => visitor.visit_pat(subpattern), Range(_) => {} Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => { for subpattern in prefix.iter() { diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 60624855fea..07964e304b9 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -144,7 +144,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { let mut targets = Vec::new(); for arm in rest { let arm = &self.thir[*arm]; - let PatKind::Constant { value, opt_def: _ } = arm.pattern.kind else { + let PatKind::Constant { value } = arm.pattern.kind else { return Err(ParseError { span: arm.pattern.span, item_description: format!("{:?}", arm.pattern.kind), diff --git a/compiler/rustc_mir_build/src/build/matches/match_pair.rs b/compiler/rustc_mir_build/src/build/matches/match_pair.rs index df3cf53eb17..6beabb5ccdb 100644 --- a/compiler/rustc_mir_build/src/build/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/build/matches/match_pair.rs @@ -129,7 +129,7 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> { } } - PatKind::Constant { value, opt_def: _ } => TestCase::Constant { value }, + PatKind::Constant { value } => TestCase::Constant { value }, PatKind::AscribeUserType { ascription: thir::Ascription { ref annotation, variance }, @@ -162,7 +162,11 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> { TestCase::Irrefutable { ascription: None, binding } } - PatKind::InlineConstant { subpattern: ref pattern, def, .. } => { + PatKind::ExpandedConstant { subpattern: ref pattern, def_id: _, is_inline: false } => { + subpairs.push(MatchPairTree::for_pattern(place_builder, pattern, cx)); + default_irrefutable() + } + PatKind::ExpandedConstant { subpattern: ref pattern, def_id, is_inline: true } => { // Apply a type ascription for the inline constant to the value at `match_pair.place` let ascription = place.map(|source| { let span = pattern.span; @@ -173,7 +177,7 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> { }) .args; let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::TypeOf( - def.to_def_id(), + def_id, ty::UserArgs { args, user_self_ty: None }, )); let annotation = ty::CanonicalUserTypeAnnotation { diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index a62d4e9d873..9f81e1052d6 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -917,7 +917,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.visit_primary_bindings(subpattern, subpattern_user_ty, f) } - PatKind::InlineConstant { ref subpattern, .. } => { + PatKind::ExpandedConstant { ref subpattern, .. } => { self.visit_primary_bindings(subpattern, pattern_user_ty, f) } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 33e194fa246..52e5f2950a5 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -332,7 +332,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { PatKind::Wild | // these just wrap other patterns, which we recurse on below. PatKind::Or { .. } | - PatKind::InlineConstant { .. } | + PatKind::ExpandedConstant { .. } | PatKind::AscribeUserType { .. } | PatKind::Error(_) => {} } @@ -386,8 +386,12 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { visit::walk_pat(self, pat); self.inside_adt = old_inside_adt; } - PatKind::InlineConstant { def, .. } => { - self.visit_inner_body(*def); + PatKind::ExpandedConstant { def_id, is_inline, .. } => { + if let Some(def) = def_id.as_local() + && *is_inline + { + self.visit_inner_body(def); + } visit::walk_pat(self, pat); } _ => { diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index edd51b521fa..1cab055864d 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -670,11 +670,13 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { let mut interpreted_as_const = None; let mut interpreted_as_const_sugg = None; - if let PatKind::Constant { opt_def: Some(def_id), .. } + if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } | PatKind::AscribeUserType { - subpattern: box Pat { kind: PatKind::Constant { opt_def: Some(def_id), .. }, .. }, + subpattern: + box Pat { kind: PatKind::ExpandedConstant { def_id, is_inline: false, .. }, .. }, .. } = pat.kind + && let DefKind::Const = self.tcx.def_kind(def_id) { let span = self.tcx.def_span(def_id); let variable = self.tcx.item_name(def_id).to_string(); @@ -1145,7 +1147,7 @@ fn report_non_exhaustive_match<'p, 'tcx>( for &arm in arms { let arm = &thir.arms[arm]; - if let PatKind::Constant { opt_def: Some(def_id), .. } = arm.pattern.kind { + if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } = arm.pattern.kind { let const_name = cx.tcx.item_name(def_id); err.span_label( arm.pattern.span, diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index 06b13274efc..82632350af5 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -266,7 +266,6 @@ impl<'tcx> ConstToPat<'tcx> { // optimization for now. ty::Str => PatKind::Constant { value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)), - opt_def: None, }, // All other references are converted into deref patterns and then recursively // convert the dereferenced constant to a pattern that is the sub-pattern of the @@ -312,17 +311,13 @@ impl<'tcx> ConstToPat<'tcx> { } else { PatKind::Constant { value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)), - opt_def: None, } } } ty::Pat(..) | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => { // The raw pointers we see here have been "vetted" by valtree construction to be // just integers, so we simply allow them. - PatKind::Constant { - value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)), - opt_def: None, - } + PatKind::Constant { value: mir::Const::Ty(ty, ty::Const::new_value(tcx, cv, ty)) } } ty::FnPtr(..) => { unreachable!( diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 11d06e5a1cc..c732eeb40a2 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -149,15 +149,18 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { None => Ok((None, None, None)), Some(expr) => { let (kind, ascr, inline_const) = match self.lower_lit(expr) { - PatKind::InlineConstant { subpattern, def } => { - (subpattern.kind, None, Some(def)) + PatKind::ExpandedConstant { subpattern, def_id, is_inline: true } => { + (subpattern.kind, None, def_id.as_local()) + } + PatKind::ExpandedConstant { subpattern, is_inline: false, .. } => { + (subpattern.kind, None, None) } PatKind::AscribeUserType { ascription, subpattern: box Pat { kind, .. } } => { (kind, Some(ascription), None) } kind => (kind, None, None), }; - let value = if let PatKind::Constant { value, opt_def: _ } = kind { + let value = if let PatKind::Constant { value } = kind { value } else { let msg = format!( @@ -251,7 +254,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { (RangeEnd::Included, Some(Ordering::Less)) => {} // `x..=y` where `x == y` and `x` and `y` are finite. (RangeEnd::Included, Some(Ordering::Equal)) if lo.is_finite() && hi.is_finite() => { - kind = PatKind::Constant { value: lo.as_finite().unwrap(), opt_def: None }; + kind = PatKind::Constant { value: lo.as_finite().unwrap() }; } // `..=x` where `x == ty::MIN`. (RangeEnd::Included, Some(Ordering::Equal)) if !lo.is_finite() => {} @@ -288,7 +291,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { }; } for def in [lo_inline, hi_inline].into_iter().flatten() { - kind = PatKind::InlineConstant { def, subpattern: Box::new(Pat { span, ty, kind }) }; + kind = PatKind::ExpandedConstant { + def_id: def.to_def_id(), + is_inline: true, + subpattern: Box::new(Pat { span, ty, kind }), + }; } Ok(kind) } @@ -562,10 +569,20 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let args = self.typeck_results.node_args(id); let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args }); - let mut pattern = self.const_to_pat(c, ty, id, span); - if let PatKind::Constant { value, opt_def: None } = pattern.kind { - pattern.kind = PatKind::Constant { value, opt_def: Some(def_id) }; - } + let subpattern = self.const_to_pat(c, ty, id, span); + let pattern = if let hir::QPath::Resolved(None, path) = qpath + && path.segments.len() == 1 + { + // We only want to mark constants when referenced as bare names that could have been + // new bindings if the `const` didn't exist. + Box::new(Pat { + span, + ty, + kind: PatKind::ExpandedConstant { subpattern, def_id, is_inline: false }, + }) + } else { + subpattern + }; if !is_associated_const { return pattern; @@ -640,7 +657,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args }; let subpattern = self.const_to_pat(ty::Const::new_unevaluated(self.tcx, ct), ty, id, span); - PatKind::InlineConstant { subpattern, def: def_id } + PatKind::ExpandedConstant { subpattern, def_id: def_id.to_def_id(), is_inline: true } } /// Converts literals, paths and negation of literals to patterns. diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 43bca812bbd..6be0ed5fb31 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -702,14 +702,15 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_pat(subpattern, depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } - PatKind::Constant { value, opt_def: _ } => { + PatKind::Constant { value } => { print_indented!(self, "Constant {", depth_lvl + 1); print_indented!(self, format!("value: {:?}", value), depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } - PatKind::InlineConstant { def, subpattern } => { - print_indented!(self, "InlineConstant {", depth_lvl + 1); - print_indented!(self, format!("def: {:?}", def), depth_lvl + 2); + PatKind::ExpandedConstant { def_id, is_inline, subpattern } => { + print_indented!(self, "ExpandedConstant {", depth_lvl + 1); + print_indented!(self, format!("def_id: {def_id:?}"), depth_lvl + 2); + print_indented!(self, format!("is_inline: {is_inline:?}"), depth_lvl + 2); print_indented!(self, "subpattern:", depth_lvl + 2); self.print_pat(subpattern, depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index ec671150c40..7cc6ba24450 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -453,7 +453,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { let fields: Vec<_>; match &pat.kind { PatKind::AscribeUserType { subpattern, .. } - | PatKind::InlineConstant { subpattern, .. } => return self.lower_pat(subpattern), + | PatKind::ExpandedConstant { subpattern, .. } => return self.lower_pat(subpattern), PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat), PatKind::Binding { subpattern: None, .. } | PatKind::Wild => { ctor = Wildcard; @@ -536,7 +536,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { ), } } - PatKind::Constant { value, opt_def: _ } => { + PatKind::Constant { value } => { match ty.kind() { ty::Bool => { ctor = match value.try_eval_bool(cx.tcx, cx.param_env) { diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 12f169d718c..637e239a570 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -370,7 +370,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> { } match pat.kind { - thir::PatKind::Constant { value, opt_def: _ } => value.has_non_region_param(), + thir::PatKind::Constant { value } => value.has_non_region_param(), thir::PatKind::Range(box thir::PatRange { lo, hi, .. }) => { lo.has_non_region_param() || hi.has_non_region_param() } diff --git a/tests/ui/consts/const-pattern-irrefutable.rs b/tests/ui/consts/const-pattern-irrefutable.rs index c590ec8fcd3..759d2e8b2ed 100644 --- a/tests/ui/consts/const-pattern-irrefutable.rs +++ b/tests/ui/consts/const-pattern-irrefutable.rs @@ -1,7 +1,7 @@ mod foo { pub const b: u8 = 2; //~^ missing patterns are not covered because `b` is interpreted as a constant pattern, not a new variable - pub const d: u8 = 2; + pub const d: (u8, u8) = (2, 1); //~^ missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable } @@ -11,6 +11,15 @@ use foo::d; const a: u8 = 2; //~^ missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable +#[derive(PartialEq)] +struct S { + foo: u8, +} + +const e: S = S { + foo: 0, +}; + fn main() { let a = 4; //~^ ERROR refutable pattern in local binding @@ -20,9 +29,15 @@ fn main() { //~^ ERROR refutable pattern in local binding //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered //~| HELP introduce a variable instead - let d = 4; + let d = (4, 4); //~^ ERROR refutable pattern in local binding - //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered + //~| patterns `(0_u8..=1_u8, _)` and `(3_u8..=u8::MAX, _)` not covered //~| HELP introduce a variable instead + let e = S { + //~^ ERROR refutable pattern in local binding + //~| pattern `S { foo: 1_u8..=u8::MAX }` not covered + //~| HELP introduce a variable instead + foo: 1, + }; fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115). } diff --git a/tests/ui/consts/const-pattern-irrefutable.stderr b/tests/ui/consts/const-pattern-irrefutable.stderr index c118ce9e48f..4206e3fe704 100644 --- a/tests/ui/consts/const-pattern-irrefutable.stderr +++ b/tests/ui/consts/const-pattern-irrefutable.stderr @@ -1,5 +1,5 @@ error[E0005]: refutable pattern in local binding - --> $DIR/const-pattern-irrefutable.rs:15:9 + --> $DIR/const-pattern-irrefutable.rs:24:9 | LL | const a: u8 = 2; | ----------- missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable @@ -15,7 +15,7 @@ LL | let a = 4; = note: the matched value is of type `u8` error[E0005]: refutable pattern in local binding - --> $DIR/const-pattern-irrefutable.rs:19:9 + --> $DIR/const-pattern-irrefutable.rs:28:9 | LL | pub const b: u8 = 2; | --------------- missing patterns are not covered because `b` is interpreted as a constant pattern, not a new variable @@ -31,21 +31,42 @@ LL | let c = 4; = note: the matched value is of type `u8` error[E0005]: refutable pattern in local binding - --> $DIR/const-pattern-irrefutable.rs:23:9 + --> $DIR/const-pattern-irrefutable.rs:32:9 | -LL | pub const d: u8 = 2; - | --------------- missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable +LL | pub const d: (u8, u8) = (2, 1); + | --------------------- missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable ... -LL | let d = 4; +LL | let d = (4, 4); | ^ | | - | patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered + | patterns `(0_u8..=1_u8, _)` and `(3_u8..=u8::MAX, _)` not covered | help: introduce a variable instead: `d_var` | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html - = note: the matched value is of type `u8` + = note: the matched value is of type `(u8, u8)` -error: aborting due to 3 previous errors +error[E0005]: refutable pattern in local binding + --> $DIR/const-pattern-irrefutable.rs:36:9 + | +LL | const e: S = S { + | ---------- missing patterns are not covered because `e` is interpreted as a constant pattern, not a new variable +... +LL | let e = S { + | ^ + | | + | pattern `S { foo: 1_u8..=u8::MAX }` not covered + | help: introduce a variable instead: `e_var` + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html +note: `S` defined here + --> $DIR/const-pattern-irrefutable.rs:15:8 + | +LL | struct S { + | ^ + = note: the matched value is of type `S` + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0005`. diff --git a/tests/ui/consts/const_in_pattern/incomplete-slice.stderr b/tests/ui/consts/const_in_pattern/incomplete-slice.stderr index bd61f43727b..c73d1f05900 100644 --- a/tests/ui/consts/const_in_pattern/incomplete-slice.stderr +++ b/tests/ui/consts/const_in_pattern/incomplete-slice.stderr @@ -3,8 +3,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered | LL | match &[][..] { | ^^^^^^^ patterns `&[]` and `&[_, _, ..]` not covered +LL | +LL | E_SL => {} + | ---- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `E_SL` | = note: the matched value is of type `&[E]` +note: constant `E_SL` defined here + --> $DIR/incomplete-slice.rs:6:1 + | +LL | const E_SL: &[E] = &[E::A]; + | ^^^^^^^^^^^^^^^^ +help: if you meant to introduce a binding, use a different name + | +LL | E_SL_var => {} + | ++++ help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ E_SL => {}, diff --git a/tests/ui/pattern/usefulness/match-arm-statics-2.stderr b/tests/ui/pattern/usefulness/match-arm-statics-2.stderr index e4dd35a5995..60b4fcca286 100644 --- a/tests/ui/pattern/usefulness/match-arm-statics-2.stderr +++ b/tests/ui/pattern/usefulness/match-arm-statics-2.stderr @@ -3,8 +3,20 @@ error[E0004]: non-exhaustive patterns: `(true, false)` not covered | LL | match (true, false) { | ^^^^^^^^^^^^^ pattern `(true, false)` not covered +LL | +LL | TRUE_TRUE => (), + | --------- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `TRUE_TRUE` | = note: the matched value is of type `(bool, bool)` +note: constant `TRUE_TRUE` defined here + --> $DIR/match-arm-statics-2.rs:14:1 + | +LL | const TRUE_TRUE: (bool, bool) = (true, true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: if you meant to introduce a binding, use a different name + | +LL | TRUE_TRUE_var => (), + | ++++ help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ (false, true) => (), diff --git a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr index a8786d02414..0a3991fe3d1 100644 --- a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr +++ b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr @@ -199,8 +199,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered | LL | match s { | ^ patterns `&[]` and `&[_, _, ..]` not covered +LL | +LL | CONST => {} + | ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST` | = note: the matched value is of type `&[bool]` +note: constant `CONST` defined here + --> $DIR/slice-patterns-exhaustiveness.rs:88:5 + | +LL | const CONST: &[bool] = &[true]; + | ^^^^^^^^^^^^^^^^^^^^ +help: if you meant to introduce a binding, use a different name + | +LL | CONST_var => {} + | ++++ help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ CONST => {}, @@ -212,8 +224,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered | LL | match s { | ^ patterns `&[]` and `&[_, _, ..]` not covered +LL | +LL | CONST => {} + | ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST` | = note: the matched value is of type `&[bool]` +note: constant `CONST` defined here + --> $DIR/slice-patterns-exhaustiveness.rs:88:5 + | +LL | const CONST: &[bool] = &[true]; + | ^^^^^^^^^^^^^^^^^^^^ +help: if you meant to introduce a binding, use a different name + | +LL | CONST_var => {} + | ++++ help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ &[false] => {}, @@ -225,8 +249,20 @@ error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered | LL | match s { | ^ patterns `&[]` and `&[_, _, ..]` not covered +... +LL | CONST => {} + | ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST` | = note: the matched value is of type `&[bool]` +note: constant `CONST` defined here + --> $DIR/slice-patterns-exhaustiveness.rs:88:5 + | +LL | const CONST: &[bool] = &[true]; + | ^^^^^^^^^^^^^^^^^^^^ +help: if you meant to introduce a binding, use a different name + | +LL | CONST_var => {} + | ++++ help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ CONST => {}, @@ -238,8 +274,20 @@ error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered | LL | match s { | ^ pattern `&[_, _, ..]` not covered +... +LL | CONST => {} + | ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST` | = note: the matched value is of type `&[bool]` +note: constant `CONST` defined here + --> $DIR/slice-patterns-exhaustiveness.rs:88:5 + | +LL | const CONST: &[bool] = &[true]; + | ^^^^^^^^^^^^^^^^^^^^ +help: if you meant to introduce a binding, use a different name + | +LL | CONST_var => {} + | ++++ help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ CONST => {}, @@ -251,8 +299,20 @@ error[E0004]: non-exhaustive patterns: `&[false]` not covered | LL | match s { | ^ pattern `&[false]` not covered +... +LL | CONST => {} + | ----- this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST` | = note: the matched value is of type `&[bool]` +note: constant `CONST` defined here + --> $DIR/slice-patterns-exhaustiveness.rs:88:5 + | +LL | const CONST: &[bool] = &[true]; + | ^^^^^^^^^^^^^^^^^^^^ +help: if you meant to introduce a binding, use a different name + | +LL | CONST_var => {} + | ++++ help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ &[_, _, ..] => {}, @@ -264,8 +324,20 @@ error[E0004]: non-exhaustive patterns: `&[false]` not covered | LL | match s1 { | ^^ pattern `&[false]` not covered +LL | +LL | CONST1 => {} + | ------ this pattern doesn't introduce a new catch-all binding, but rather pattern matches against the value of constant `CONST1` | = note: the matched value is of type `&[bool; 1]` +note: constant `CONST1` defined here + --> $DIR/slice-patterns-exhaustiveness.rs:124:5 + | +LL | const CONST1: &[bool; 1] = &[true]; + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: if you meant to introduce a binding, use a different name + | +LL | CONST1_var => {} + | ++++ help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ CONST1 => {}, From f1772d57399272f69fa69ad10ae21d380efc2e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 7 Nov 2024 19:40:27 +0000 Subject: [PATCH 08/16] Make suggestion verbose --- compiler/rustc_mir_build/src/errors.rs | 3 +- .../2229_closure_analysis/bad-pattern.stderr | 9 ++--- .../consts/const-pattern-irrefutable.stderr | 36 ++++++++++--------- tests/ui/mir/issue-112269.stderr | 18 +++++----- ...const-pat-non-exaustive-let-new-var.stderr | 9 ++--- 5 files changed, 42 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 04eb7ffe776..4443d9aebc6 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -913,7 +913,8 @@ impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> { #[suggestion( mir_build_interpreted_as_const, code = "{variable}_var", - applicability = "maybe-incorrect" + applicability = "maybe-incorrect", + style = "verbose" )] pub(crate) struct InterpretedAsConst { #[primary_span] diff --git a/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr b/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr index 5692d530b06..5f980c46a1f 100644 --- a/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr +++ b/tests/ui/closures/2229_closure_analysis/bad-pattern.stderr @@ -101,14 +101,15 @@ LL | const PAT: u32 = 0; | -------------- missing patterns are not covered because `PAT` is interpreted as a constant pattern, not a new variable ... LL | let PAT = v1; - | ^^^ - | | - | pattern `1_u32..=u32::MAX` not covered - | help: introduce a variable instead: `PAT_var` + | ^^^ pattern `1_u32..=u32::MAX` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `u32` +help: introduce a variable instead + | +LL | let PAT_var = v1; + | ~~~~~~~ error: aborting due to 7 previous errors diff --git a/tests/ui/consts/const-pattern-irrefutable.stderr b/tests/ui/consts/const-pattern-irrefutable.stderr index 4206e3fe704..afb67a3a118 100644 --- a/tests/ui/consts/const-pattern-irrefutable.stderr +++ b/tests/ui/consts/const-pattern-irrefutable.stderr @@ -5,14 +5,15 @@ LL | const a: u8 = 2; | ----------- missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable ... LL | let a = 4; - | ^ - | | - | patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - | help: introduce a variable instead: `a_var` + | ^ patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `u8` +help: introduce a variable instead + | +LL | let a_var = 4; + | ~~~~~ error[E0005]: refutable pattern in local binding --> $DIR/const-pattern-irrefutable.rs:28:9 @@ -21,14 +22,15 @@ LL | pub const b: u8 = 2; | --------------- missing patterns are not covered because `b` is interpreted as a constant pattern, not a new variable ... LL | let c = 4; - | ^ - | | - | patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered - | help: introduce a variable instead: `b_var` + | ^ patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `u8` +help: introduce a variable instead + | +LL | let b_var = 4; + | ~~~~~ error[E0005]: refutable pattern in local binding --> $DIR/const-pattern-irrefutable.rs:32:9 @@ -37,14 +39,15 @@ LL | pub const d: (u8, u8) = (2, 1); | --------------------- missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable ... LL | let d = (4, 4); - | ^ - | | - | patterns `(0_u8..=1_u8, _)` and `(3_u8..=u8::MAX, _)` not covered - | help: introduce a variable instead: `d_var` + | ^ patterns `(0_u8..=1_u8, _)` and `(3_u8..=u8::MAX, _)` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `(u8, u8)` +help: introduce a variable instead + | +LL | let d_var = (4, 4); + | ~~~~~ error[E0005]: refutable pattern in local binding --> $DIR/const-pattern-irrefutable.rs:36:9 @@ -53,10 +56,7 @@ LL | const e: S = S { | ---------- missing patterns are not covered because `e` is interpreted as a constant pattern, not a new variable ... LL | let e = S { - | ^ - | | - | pattern `S { foo: 1_u8..=u8::MAX }` not covered - | help: introduce a variable instead: `e_var` + | ^ pattern `S { foo: 1_u8..=u8::MAX }` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html @@ -66,6 +66,10 @@ note: `S` defined here LL | struct S { | ^ = note: the matched value is of type `S` +help: introduce a variable instead + | +LL | let e_var = S { + | ~~~~~ error: aborting due to 4 previous errors diff --git a/tests/ui/mir/issue-112269.stderr b/tests/ui/mir/issue-112269.stderr index 945a7e25dd0..adb662c98a7 100644 --- a/tests/ui/mir/issue-112269.stderr +++ b/tests/ui/mir/issue-112269.stderr @@ -4,14 +4,15 @@ error[E0005]: refutable pattern in local binding LL | const x: i32 = 4; | ------------ missing patterns are not covered because `x` is interpreted as a constant pattern, not a new variable LL | let x: i32 = 3; - | ^ - | | - | patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered - | help: introduce a variable instead: `x_var` + | ^ patterns `i32::MIN..=3_i32` and `5_i32..=i32::MAX` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` +help: introduce a variable instead + | +LL | let x_var: i32 = 3; + | ~~~~~ error[E0005]: refutable pattern in local binding --> $DIR/issue-112269.rs:7:9 @@ -19,14 +20,15 @@ error[E0005]: refutable pattern in local binding LL | const y: i32 = 3; | ------------ missing patterns are not covered because `y` is interpreted as a constant pattern, not a new variable LL | let y = 4; - | ^ - | | - | patterns `i32::MIN..=2_i32` and `4_i32..=i32::MAX` not covered - | help: introduce a variable instead: `y_var` + | ^ patterns `i32::MIN..=2_i32` and `4_i32..=i32::MAX` not covered | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` +help: introduce a variable instead + | +LL | let y_var = 4; + | ~~~~~ error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr index 29c4b2905eb..a275d8e4e83 100644 --- a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr +++ b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr @@ -2,10 +2,7 @@ error[E0005]: refutable pattern in local binding --> $DIR/const-pat-non-exaustive-let-new-var.rs:2:9 | LL | let A = 3; - | ^ - | | - | patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered - | help: introduce a variable instead: `A_var` + | ^ patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered ... LL | const A: i32 = 2; | ------------ missing patterns are not covered because `A` is interpreted as a constant pattern, not a new variable @@ -13,6 +10,10 @@ LL | const A: i32 = 2; = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html = note: the matched value is of type `i32` +help: introduce a variable instead + | +LL | let A_var = 3; + | ~~~~~ error: aborting due to 1 previous error From bb37e5d3cd4aace7141f5dfce401f6532cdb4d87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Tue, 12 Nov 2024 00:59:11 +0000 Subject: [PATCH 09/16] review comments --- compiler/rustc_middle/src/thir.rs | 7 +++++-- compiler/rustc_mir_build/src/thir/pattern/check_match.rs | 4 ---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index f37c8486df5..d50d2e19f2d 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -789,11 +789,14 @@ pub enum PatKind<'tcx> { }, /// Inline or named constant found while lowering a pattern. + /// + /// We only mark patterns referencing constants when they are bare names that could have been + /// new bindings if the `const` didn't exist. ExpandedConstant { /// [DefId] of the constant, we need this so that we have a /// reference that can be used by unsafety checking to visit nested - /// unevaluated constants. If the `DefId` doesn't correspond to a local - /// crate, it points at the `const` item. + /// unevaluated constants and for diagnostics. If the `DefId` doesn't + /// correspond to a local crate, it points at the `const` item. def_id: DefId, /// If `false`, then `def_id` points at a `const` item, otherwise it /// corresponds to a local inline const. diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 1cab055864d..db0f8a28293 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -696,10 +696,6 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { misc_suggestion = Some(MiscPatternSuggestion::AttemptedIntegerLiteral { start_span: pat.span.shrink_to_lo(), }); - } else if snippet.chars().all(|c| c.is_alphanumeric() || c == '_') { - interpreted_as_const = Some(pat.span); - interpreted_as_const_sugg = - Some(InterpretedAsConst { span: pat.span, variable: snippet }); } } From 6480b76e458c14a87ea3c41f1eb96aa141044565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 13 Nov 2024 21:54:46 +0000 Subject: [PATCH 10/16] review comments - Remove check for "how many path segments is the pattern" - Check before suggesting if the path has multiple path segments --- .../src/thir/pattern/check_match.rs | 9 ++++- .../rustc_mir_build/src/thir/pattern/mod.rs | 38 +++++++++---------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index db0f8a28293..4b872d9b7f7 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -677,6 +677,9 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { .. } = pat.kind && let DefKind::Const = self.tcx.def_kind(def_id) + && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(pat.span) + // We filter out paths with multiple path::segments. + && snippet.chars().all(|c| c.is_alphanumeric() || c == '_') { let span = self.tcx.def_span(def_id); let variable = self.tcx.item_name(def_id).to_string(); @@ -1143,7 +1146,11 @@ fn report_non_exhaustive_match<'p, 'tcx>( for &arm in arms { let arm = &thir.arms[arm]; - if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } = arm.pattern.kind { + if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } = arm.pattern.kind + && let Ok(snippet) = cx.tcx.sess.source_map().span_to_snippet(arm.pattern.span) + // We filter out paths with multiple path::segments. + && snippet.chars().all(|c| c.is_alphanumeric() || c == '_') + { let const_name = cx.tcx.item_name(def_id); err.span_label( arm.pattern.span, diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index c732eeb40a2..9b63d788194 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -160,13 +160,19 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } kind => (kind, None, None), }; - let value = if let PatKind::Constant { value } = kind { - value - } else { - let msg = format!( - "found bad range pattern endpoint `{expr:?}` outside of error recovery" - ); - return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg)); + let value = match kind { + PatKind::Constant { value } => value, + PatKind::ExpandedConstant { subpattern, .. } + if let PatKind::Constant { value } = subpattern.kind => + { + value + } + _ => { + let msg = format!( + "found bad range pattern endpoint `{expr:?}` outside of error recovery" + ); + return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg)); + } }; Ok((Some(PatRangeBoundary::Finite(value)), ascr, inline_const)) } @@ -570,19 +576,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let args = self.typeck_results.node_args(id); let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args }); let subpattern = self.const_to_pat(c, ty, id, span); - let pattern = if let hir::QPath::Resolved(None, path) = qpath - && path.segments.len() == 1 - { - // We only want to mark constants when referenced as bare names that could have been - // new bindings if the `const` didn't exist. - Box::new(Pat { - span, - ty, - kind: PatKind::ExpandedConstant { subpattern, def_id, is_inline: false }, - }) - } else { - subpattern - }; + let pattern = Box::new(Pat { + span, + ty, + kind: PatKind::ExpandedConstant { subpattern, def_id, is_inline: false }, + }); if !is_associated_const { return pattern; From 912ee65ccdad256c855a2ae67925ca7efd2eee99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 17 Nov 2024 23:39:51 +0000 Subject: [PATCH 11/16] review comment: modify doc comment --- compiler/rustc_middle/src/thir.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index d50d2e19f2d..70df2379016 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -788,10 +788,8 @@ pub enum PatKind<'tcx> { value: mir::Const<'tcx>, }, - /// Inline or named constant found while lowering a pattern. - /// - /// We only mark patterns referencing constants when they are bare names that could have been - /// new bindings if the `const` didn't exist. + /// Pattern obtained by converting a constant (inline or named) to its pattern + /// representation using `const_to_pat`. ExpandedConstant { /// [DefId] of the constant, we need this so that we have a /// reference that can be used by unsafety checking to visit nested From 29acf8b422ab446fa4cd51fbb0e5a145f30c1cfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Sun, 17 Nov 2024 23:58:22 +0000 Subject: [PATCH 12/16] Account for `ExpandedConstant` in `parse_match` --- .../src/build/custom/parse/instruction.rs | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 07964e304b9..62d173987fc 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -144,12 +144,20 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { let mut targets = Vec::new(); for arm in rest { let arm = &self.thir[*arm]; - let PatKind::Constant { value } = arm.pattern.kind else { - return Err(ParseError { - span: arm.pattern.span, - item_description: format!("{:?}", arm.pattern.kind), - expected: "constant pattern".to_string(), - }); + let value = match arm.pattern.kind { + PatKind::Constant { value } => value, + PatKind::ExpandedConstant { ref subpattern, def_id: _, is_inline: false } + if let PatKind::Constant { value } = subpattern.kind => + { + value + } + _ => { + return Err(ParseError { + span: arm.pattern.span, + item_description: format!("{:?}", arm.pattern.kind), + expected: "constant pattern".to_string(), + }); + } }; values.push(value.eval_bits(self.tcx, self.param_env)); targets.push(self.parse_block(arm.body)?); From f37d021d6ccb7949ba8e8b2a5d6e91686063da2a Mon Sep 17 00:00:00 2001 From: daxpedda Date: Wed, 20 Nov 2024 13:48:48 +0100 Subject: [PATCH 13/16] Account for `wasm32v1-none` when exporting TLS symbols --- compiler/rustc_codegen_ssa/src/back/linker.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 4f3664a503d..6ee599c9964 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1279,7 +1279,7 @@ impl<'a> WasmLd<'a> { let mut wasm_ld = WasmLd { cmd, sess }; if sess.target_features.contains(&sym::atomics) { wasm_ld.link_args(&["--shared-memory", "--max-memory=1073741824", "--import-memory"]); - if sess.target.os == "unknown" { + if sess.target.os == "unknown" || sess.target.os == "none" { wasm_ld.link_args(&[ "--export=__wasm_init_tls", "--export=__tls_size", @@ -1403,7 +1403,7 @@ impl<'a> Linker for WasmLd<'a> { // symbols explicitly passed via the `--export` flags above and hides all // others. Various bits and pieces of wasm32-unknown-unknown tooling use // this, so be sure these symbols make their way out of the linker as well. - if self.sess.target.os == "unknown" { + if self.sess.target.os == "unknown" || self.sess.target.os == "none" { self.link_args(&["--export=__heap_base", "--export=__data_end"]); } } From 06e66d78c3a104b30fd59714d4dbb1a5d9f351bb Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 19 Nov 2024 21:23:10 +0000 Subject: [PATCH 14/16] Rip out built-in PointerLike impl --- compiler/rustc_middle/src/ty/context.rs | 14 --------- .../src/solve/assembly/mod.rs | 10 ------ .../src/solve/effect_goals.rs | 7 ----- .../src/solve/normalizes_to/mod.rs | 7 ----- .../src/solve/trait_goals.rs | 26 ---------------- .../src/traits/select/candidate_assembly.rs | 31 ------------------- compiler/rustc_type_ir/src/interner.rs | 9 +----- compiler/rustc_type_ir/src/lang_items.rs | 1 - 8 files changed, 1 insertion(+), 104 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index ad42eacf823..b4d29f08a0f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -602,19 +602,6 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.coroutine_is_async_gen(coroutine_def_id) } - // We don't use `TypingEnv` here as it's only defined in `rustc_middle` and - // `rustc_next_trait_solver` shouldn't have to know about it. - fn layout_is_pointer_like( - self, - typing_mode: ty::TypingMode<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - ) -> bool { - let typing_env = ty::TypingEnv { typing_mode, param_env }; - self.layout_of(self.erase_regions(typing_env).as_query_input(self.erase_regions(ty))) - .is_ok_and(|layout| layout.layout.is_pointer_like(&self.data_layout)) - } - type UnsizingParams = &'tcx rustc_index::bit_set::BitSet; fn unsizing_params_for_adt(self, adt_def_id: DefId) -> Self::UnsizingParams { self.unsizing_params_for_adt(adt_def_id) @@ -688,7 +675,6 @@ bidirectional_lang_item_map! { Metadata, Option, PointeeTrait, - PointerLike, Poll, Sized, TransmuteTrait, diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index ebf7372926f..78344571088 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -159,13 +159,6 @@ where goal: Goal, ) -> Result, NoSolution>; - /// A type is `PointerLike` if we can compute its layout, and that layout - /// matches the layout of `usize`. - fn consider_builtin_pointer_like_candidate( - ecx: &mut EvalCtxt<'_, D>, - goal: Goal, - ) -> Result, NoSolution>; - /// A type is a `FnPtr` if it is of `FnPtr` type. fn consider_builtin_fn_ptr_trait_candidate( ecx: &mut EvalCtxt<'_, D>, @@ -449,9 +442,6 @@ where ty::ClosureKind::FnOnce, ) } - Some(TraitSolverLangItem::PointerLike) => { - G::consider_builtin_pointer_like_candidate(self, goal) - } Some(TraitSolverLangItem::FnPtrTrait) => { G::consider_builtin_fn_ptr_trait_candidate(self, goal) } diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs index 282ca2fedbc..1f5ca71dd6f 100644 --- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs @@ -210,13 +210,6 @@ where Err(NoSolution) } - fn consider_builtin_pointer_like_candidate( - _ecx: &mut EvalCtxt<'_, D>, - _goal: Goal, - ) -> Result, NoSolution> { - unreachable!("PointerLike is not const") - } - fn consider_builtin_fn_ptr_trait_candidate( _ecx: &mut EvalCtxt<'_, D>, _goal: Goal, diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 8a01659953d..6b407640426 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -363,13 +363,6 @@ where panic!("`Copy`/`Clone` does not have an associated type: {:?}", goal); } - fn consider_builtin_pointer_like_candidate( - _ecx: &mut EvalCtxt<'_, D>, - goal: Goal, - ) -> Result, NoSolution> { - panic!("`PointerLike` does not have an associated type: {:?}", goal); - } - fn consider_builtin_fn_ptr_trait_candidate( _ecx: &mut EvalCtxt<'_, D>, goal: Goal, diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index e64d4eed9d8..ce16258d180 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -248,32 +248,6 @@ where ) } - fn consider_builtin_pointer_like_candidate( - ecx: &mut EvalCtxt<'_, D>, - goal: Goal, - ) -> Result, NoSolution> { - if goal.predicate.polarity != ty::PredicatePolarity::Positive { - return Err(NoSolution); - } - - let cx = ecx.cx(); - // But if there are inference variables, we have to wait until it's resolved. - if (goal.param_env, goal.predicate.self_ty()).has_non_region_infer() { - return ecx.forced_ambiguity(MaybeCause::Ambiguity); - } - - if cx.layout_is_pointer_like( - ecx.typing_mode(goal.param_env), - goal.param_env, - goal.predicate.self_ty(), - ) { - ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) - .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) - } else { - Err(NoSolution) - } - } - fn consider_builtin_fn_ptr_trait_candidate( ecx: &mut EvalCtxt<'_, D>, goal: Goal, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 1e0c487c4d4..345e1cc31f3 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -111,8 +111,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_candidates_for_transmutability(obligation, &mut candidates); } else if tcx.is_lang_item(def_id, LangItem::Tuple) { self.assemble_candidate_for_tuple(obligation, &mut candidates); - } else if tcx.is_lang_item(def_id, LangItem::PointerLike) { - self.assemble_candidate_for_pointer_like(obligation, &mut candidates); } else if tcx.is_lang_item(def_id, LangItem::FnPtrTrait) { self.assemble_candidates_for_fn_ptr_trait(obligation, &mut candidates); } else { @@ -1216,35 +1214,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - fn assemble_candidate_for_pointer_like( - &mut self, - obligation: &PolyTraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) { - // The regions of a type don't affect the size of the type - let tcx = self.tcx(); - let self_ty = tcx.instantiate_bound_regions_with_erased(obligation.predicate.self_ty()); - - // But if there are inference variables, we have to wait until it's resolved. - if (obligation.param_env, self_ty).has_non_region_infer() { - candidates.ambiguous = true; - return; - } - - // We should erase regions from both the param-env and type, since both - // may have infer regions. Specifically, after canonicalizing and instantiating, - // early bound regions turn into region vars in both the new and old solver. - let key = self.infcx.pseudo_canonicalize_query( - tcx.erase_regions(obligation.param_env), - tcx.erase_regions(self_ty), - ); - if let Ok(layout) = tcx.layout_of(key) - && layout.layout.is_pointer_like(&tcx.data_layout) - { - candidates.vec.push(BuiltinCandidate { has_nested: false }); - } - } - fn assemble_candidates_for_fn_ptr_trait( &mut self, obligation: &PolyTraitObligation<'tcx>, diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 6e6cf91d855..4e1715dbd0f 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -13,7 +13,7 @@ use crate::lang_items::TraitSolverLangItem; use crate::relate::Relate; use crate::solve::{CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult}; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; -use crate::{self as ty, TypingMode, search_graph}; +use crate::{self as ty, search_graph}; pub trait Interner: Sized @@ -278,13 +278,6 @@ pub trait Interner: fn coroutine_is_gen(self, coroutine_def_id: Self::DefId) -> bool; fn coroutine_is_async_gen(self, coroutine_def_id: Self::DefId) -> bool; - fn layout_is_pointer_like( - self, - typing_mode: TypingMode, - param_env: Self::ParamEnv, - ty: Self::Ty, - ) -> bool; - type UnsizingParams: Deref>; fn unsizing_params_for_adt(self, adt_def_id: Self::DefId) -> Self::UnsizingParams; diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index d6ca22a90a4..df43346065d 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -31,7 +31,6 @@ pub enum TraitSolverLangItem { Metadata, Option, PointeeTrait, - PointerLike, Poll, Sized, TransmuteTrait, From 228068bc6efb16f359b5318e66fa789c2f58ce60 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 20 Nov 2024 02:46:56 +0000 Subject: [PATCH 15/16] Make PointerLike opt-in as a trait --- .../src/coherence/builtin.rs | 85 ++++++++++++++++--- library/alloc/src/boxed.rs | 6 ++ library/alloc/src/lib.rs | 1 + library/core/src/marker.rs | 12 +++ tests/crashes/113280.rs | 16 ---- tests/crashes/127676.rs | 8 -- tests/ui/dyn-star/async-block-dyn-star.rs | 9 ++ tests/ui/dyn-star/async-block-dyn-star.stderr | 20 +++++ ...ize-at-cast-polymorphic-bad.current.stderr | 11 ++- ...k-size-at-cast-polymorphic-bad.next.stderr | 11 ++- tests/ui/dyn-star/drop.rs | 7 +- tests/ui/dyn-star/enum-cast.rs | 7 +- tests/ui/dyn-star/error.rs | 2 +- tests/ui/dyn-star/error.stderr | 4 +- tests/ui/dyn-star/float-as-dyn-star.rs | 16 ++++ tests/ui/dyn-star/float-as-dyn-star.stderr | 21 +++++ tests/ui/dyn-star/upcast.stderr | 10 ++- 17 files changed, 194 insertions(+), 52 deletions(-) delete mode 100644 tests/crashes/113280.rs delete mode 100644 tests/crashes/127676.rs create mode 100644 tests/ui/dyn-star/async-block-dyn-star.rs create mode 100644 tests/ui/dyn-star/async-block-dyn-star.stderr create mode 100644 tests/ui/dyn-star/float-as-dyn-star.rs create mode 100644 tests/ui/dyn-star/float-as-dyn-star.stderr diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index c2ad61820a7..3b49bc41ffe 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -37,22 +37,19 @@ pub(super) fn check_trait<'tcx>( ) -> Result<(), ErrorGuaranteed> { let lang_items = tcx.lang_items(); let checker = Checker { tcx, trait_def_id, impl_def_id, impl_header }; - let mut res = checker.check(lang_items.drop_trait(), visit_implementation_of_drop); - res = res.and(checker.check(lang_items.copy_trait(), visit_implementation_of_copy)); - res = res.and(checker.check(lang_items.const_param_ty_trait(), |checker| { + checker.check(lang_items.drop_trait(), visit_implementation_of_drop)?; + checker.check(lang_items.copy_trait(), visit_implementation_of_copy)?; + checker.check(lang_items.const_param_ty_trait(), |checker| { visit_implementation_of_const_param_ty(checker, LangItem::ConstParamTy) - })); - res = res.and(checker.check(lang_items.unsized_const_param_ty_trait(), |checker| { + })?; + checker.check(lang_items.unsized_const_param_ty_trait(), |checker| { visit_implementation_of_const_param_ty(checker, LangItem::UnsizedConstParamTy) - })); - - res = res.and( - checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized), - ); - res.and( - checker - .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn), - ) + })?; + checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)?; + checker + .check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn)?; + checker.check(lang_items.pointer_like(), visit_implementation_of_pointer_like)?; + Ok(()) } struct Checker<'tcx> { @@ -663,3 +660,63 @@ fn infringing_fields_error<'tcx>( err.emit() } + +fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> { + let tcx = checker.tcx; + let typing_env = ty::TypingEnv::non_body_analysis(tcx, checker.impl_def_id); + let impl_span = tcx.def_span(checker.impl_def_id); + let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty(); + + // If an ADT is repr(transparent)... + if let ty::Adt(def, args) = *self_ty.kind() + && def.repr().transparent() + { + // FIXME(compiler-errors): This should and could be deduplicated into a query. + // Find the nontrivial field. + let adt_typing_env = ty::TypingEnv::non_body_analysis(tcx, def.did()); + let nontrivial_field = def.all_fields().find(|field_def| { + let field_ty = tcx.type_of(field_def.did).instantiate_identity(); + !tcx.layout_of(adt_typing_env.as_query_input(field_ty)) + .is_ok_and(|layout| layout.layout.is_1zst()) + }); + + if let Some(nontrivial_field) = nontrivial_field { + // Check that the nontrivial field implements `PointerLike`. + let nontrivial_field = nontrivial_field.ty(tcx, args); + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); + let ocx = ObligationCtxt::new(&infcx); + ocx.register_bound( + ObligationCause::misc(impl_span, checker.impl_def_id), + param_env, + nontrivial_field, + tcx.lang_items().pointer_like().unwrap(), + ); + // FIXME(dyn-star): We should regionck this implementation. + if ocx.select_all_or_error().is_empty() { + return Ok(()); + } + } + } + + let is_permitted_primitive = match *self_ty.kind() { + ty::Adt(def, _) => def.is_box(), + ty::Uint(..) | ty::Int(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) => true, + _ => false, + }; + + if is_permitted_primitive + && let Ok(layout) = tcx.layout_of(typing_env.as_query_input(self_ty)) + && layout.layout.is_pointer_like(&tcx.data_layout) + { + return Ok(()); + } + + Err(tcx + .dcx() + .struct_span_err( + impl_span, + "implementation must be applied to type that has the same ABI as a pointer, \ + or is `repr(transparent)` and whose field is `PointerLike`", + ) + .emit()) +} diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index ac3e4626ee5..ee60ec0fbac 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -191,6 +191,8 @@ use core::error::{self, Error}; use core::fmt; use core::future::Future; use core::hash::{Hash, Hasher}; +#[cfg(not(bootstrap))] +use core::marker::PointerLike; use core::marker::{Tuple, Unsize}; use core::mem::{self, SizedTypeProperties}; use core::ops::{ @@ -2131,3 +2133,7 @@ impl Error for Box { Error::provide(&**self, request); } } + +#[cfg(not(bootstrap))] +#[unstable(feature = "pointer_like_trait", issue = "none")] +impl PointerLike for Box {} diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 7839fe04b8d..041ff37897f 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -136,6 +136,7 @@ #![feature(panic_internals)] #![feature(pattern)] #![feature(pin_coerce_unsized_trait)] +#![feature(pointer_like_trait)] #![feature(ptr_internals)] #![feature(ptr_metadata)] #![feature(ptr_sub_ptr)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 1c5c58d64a2..c8ea52a1fb0 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -981,6 +981,18 @@ pub trait Tuple {} )] pub trait PointerLike {} +#[cfg(not(bootstrap))] +marker_impls! { + #[unstable(feature = "pointer_like_trait", issue = "none")] + PointerLike for + usize, + {T} &T, + {T} &mut T, + {T} *const T, + {T} *mut T, + {T: PointerLike} crate::pin::Pin, +} + /// A marker for types which can be used as types of `const` generic parameters. /// /// These types must have a proper equivalence relation (`Eq`) and it must be automatically diff --git a/tests/crashes/113280.rs b/tests/crashes/113280.rs deleted file mode 100644 index 86677f416fe..00000000000 --- a/tests/crashes/113280.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ known-bug: #113280 -//@ only-x86_64 - -#![feature(dyn_star, pointer_like_trait)] -#![allow(incomplete_features)] - -use std::fmt::Debug; -use std::marker::PointerLike; - -fn make_dyn_star<'a>(t: impl PointerLike + Debug + 'a) -> dyn* Debug + 'a { - f32::from_bits(0x1) as f64 -} - -fn main() { - println!("{:?}", make_dyn_star(Box::new(1i32))); -} diff --git a/tests/crashes/127676.rs b/tests/crashes/127676.rs deleted file mode 100644 index 81149c2ef84..00000000000 --- a/tests/crashes/127676.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #127676 -//@ edition:2018 - -#![feature(dyn_star,const_async_blocks)] - -static S: dyn* Send + Sync = async { 42 }; - -pub fn main() {} diff --git a/tests/ui/dyn-star/async-block-dyn-star.rs b/tests/ui/dyn-star/async-block-dyn-star.rs new file mode 100644 index 00000000000..9bffd6c6725 --- /dev/null +++ b/tests/ui/dyn-star/async-block-dyn-star.rs @@ -0,0 +1,9 @@ +//@ edition:2018 + +#![feature(dyn_star, const_async_blocks)] +//~^ WARN the feature `dyn_star` is incomplete + +static S: dyn* Send + Sync = async { 42 }; +//~^ needs to have the same ABI as a pointer + +pub fn main() {} diff --git a/tests/ui/dyn-star/async-block-dyn-star.stderr b/tests/ui/dyn-star/async-block-dyn-star.stderr new file mode 100644 index 00000000000..f62c85c0ad2 --- /dev/null +++ b/tests/ui/dyn-star/async-block-dyn-star.stderr @@ -0,0 +1,20 @@ +warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/async-block-dyn-star.rs:3:12 + | +LL | #![feature(dyn_star, const_async_blocks)] + | ^^^^^^^^ + | + = note: see issue #102425 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}` needs to have the same ABI as a pointer + --> $DIR/async-block-dyn-star.rs:6:30 + | +LL | static S: dyn* Send + Sync = async { 42 }; + | ^^^^^^^^^^^^ `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}` needs to be a pointer-like type + | + = help: the trait `PointerLike` is not implemented for `{async block@$DIR/async-block-dyn-star.rs:6:30: 6:35}` + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr index 7b5ea7bb707..a0aff69f396 100644 --- a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr +++ b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.current.stderr @@ -1,14 +1,17 @@ error[E0277]: `&T` needs to have the same ABI as a pointer --> $DIR/check-size-at-cast-polymorphic-bad.rs:15:15 | +LL | fn polymorphic(t: &T) { + | - this type parameter needs to be `Sized` LL | dyn_debug(t); | ^ `&T` needs to be a pointer-like type | - = help: the trait `PointerLike` is not implemented for `&T` -help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + = note: required for `&T` to implement `PointerLike` +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - fn polymorphic(t: &T) { +LL + fn polymorphic(t: &T) { | -LL | fn polymorphic(t: &T) where &T: PointerLike { - | +++++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr index 7b5ea7bb707..a0aff69f396 100644 --- a/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr +++ b/tests/ui/dyn-star/check-size-at-cast-polymorphic-bad.next.stderr @@ -1,14 +1,17 @@ error[E0277]: `&T` needs to have the same ABI as a pointer --> $DIR/check-size-at-cast-polymorphic-bad.rs:15:15 | +LL | fn polymorphic(t: &T) { + | - this type parameter needs to be `Sized` LL | dyn_debug(t); | ^ `&T` needs to be a pointer-like type | - = help: the trait `PointerLike` is not implemented for `&T` -help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement + = note: required for `&T` to implement `PointerLike` +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - fn polymorphic(t: &T) { +LL + fn polymorphic(t: &T) { | -LL | fn polymorphic(t: &T) where &T: PointerLike { - | +++++++++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/dyn-star/drop.rs b/tests/ui/dyn-star/drop.rs index ca86f1b5b01..bc746331527 100644 --- a/tests/ui/dyn-star/drop.rs +++ b/tests/ui/dyn-star/drop.rs @@ -1,13 +1,18 @@ //@ run-pass //@ check-run-results -#![feature(dyn_star)] +#![feature(dyn_star, pointer_like_trait)] #![allow(incomplete_features)] use std::fmt::Debug; +use std::marker::PointerLike; #[derive(Debug)] +#[repr(transparent)] struct Foo(#[allow(dead_code)] usize); +// FIXME(dyn_star): Make this into a derive. +impl PointerLike for Foo {} + impl Drop for Foo { fn drop(&mut self) { println!("destructor called"); diff --git a/tests/ui/dyn-star/enum-cast.rs b/tests/ui/dyn-star/enum-cast.rs index 6e895e9527a..3cc7390eb12 100644 --- a/tests/ui/dyn-star/enum-cast.rs +++ b/tests/ui/dyn-star/enum-cast.rs @@ -3,13 +3,18 @@ // This used to ICE, because the compiler confused a pointer-like to dyn* coercion // with a c-like enum to integer cast. -#![feature(dyn_star)] +#![feature(dyn_star, pointer_like_trait)] #![expect(incomplete_features)] +use std::marker::PointerLike; + +#[repr(transparent)] enum E { Num(usize), } +impl PointerLike for E {} + trait Trait {} impl Trait for E {} diff --git a/tests/ui/dyn-star/error.rs b/tests/ui/dyn-star/error.rs index d8261387efa..7288596f3fa 100644 --- a/tests/ui/dyn-star/error.rs +++ b/tests/ui/dyn-star/error.rs @@ -7,7 +7,7 @@ trait Foo {} fn make_dyn_star() { let i = 42; - let dyn_i: dyn* Foo = i; //~ ERROR trait bound `{integer}: Foo` is not satisfied + let dyn_i: dyn* Foo = i; //~ ERROR trait bound `usize: Foo` is not satisfied } fn main() {} diff --git a/tests/ui/dyn-star/error.stderr b/tests/ui/dyn-star/error.stderr index a9f4a054519..55981c03bac 100644 --- a/tests/ui/dyn-star/error.stderr +++ b/tests/ui/dyn-star/error.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `{integer}: Foo` is not satisfied +error[E0277]: the trait bound `usize: Foo` is not satisfied --> $DIR/error.rs:10:27 | LL | let dyn_i: dyn* Foo = i; - | ^ the trait `Foo` is not implemented for `{integer}` + | ^ the trait `Foo` is not implemented for `usize` | help: this trait has no implementations, consider adding one --> $DIR/error.rs:6:1 diff --git a/tests/ui/dyn-star/float-as-dyn-star.rs b/tests/ui/dyn-star/float-as-dyn-star.rs new file mode 100644 index 00000000000..1b629c64c25 --- /dev/null +++ b/tests/ui/dyn-star/float-as-dyn-star.rs @@ -0,0 +1,16 @@ +//@ only-x86_64 + +#![feature(dyn_star, pointer_like_trait)] +//~^ WARN the feature `dyn_star` is incomplete + +use std::fmt::Debug; +use std::marker::PointerLike; + +fn make_dyn_star() -> dyn* Debug + 'static { + f32::from_bits(0x1) as f64 + //~^ ERROR `f64` needs to have the same ABI as a pointer +} + +fn main() { + println!("{:?}", make_dyn_star()); +} diff --git a/tests/ui/dyn-star/float-as-dyn-star.stderr b/tests/ui/dyn-star/float-as-dyn-star.stderr new file mode 100644 index 00000000000..9caba512e5f --- /dev/null +++ b/tests/ui/dyn-star/float-as-dyn-star.stderr @@ -0,0 +1,21 @@ +warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/float-as-dyn-star.rs:3:12 + | +LL | #![feature(dyn_star, pointer_like_trait)] + | ^^^^^^^^ + | + = note: see issue #102425 for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: `f64` needs to have the same ABI as a pointer + --> $DIR/float-as-dyn-star.rs:10:5 + | +LL | f32::from_bits(0x1) as f64 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `f64` needs to be a pointer-like type + | + = help: the trait `PointerLike` is not implemented for `f64` + = help: the trait `PointerLike` is implemented for `usize` + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/dyn-star/upcast.stderr b/tests/ui/dyn-star/upcast.stderr index adef9525bf1..801e1c233c1 100644 --- a/tests/ui/dyn-star/upcast.stderr +++ b/tests/ui/dyn-star/upcast.stderr @@ -7,6 +7,14 @@ LL | #![feature(dyn_star, trait_upcasting)] = note: see issue #102425 for more information = note: `#[warn(incomplete_features)]` on by default +error[E0277]: `W` needs to have the same ABI as a pointer + --> $DIR/upcast.rs:28:23 + | +LL | let w: dyn* Foo = W(0); + | ^^^^ `W` needs to be a pointer-like type + | + = help: the trait `PointerLike` is not implemented for `W` + error[E0277]: `dyn* Foo` needs to have the same ABI as a pointer --> $DIR/upcast.rs:30:23 | @@ -15,6 +23,6 @@ LL | let w: dyn* Bar = w; | = help: the trait `PointerLike` is not implemented for `dyn* Foo` -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0277`. From 186e282a43f384d456579ab50c5d6a48fd5cca1b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 20 Nov 2024 18:11:37 +0100 Subject: [PATCH 16/16] Add `UnordMap::clear` method --- compiler/rustc_data_structures/src/unord.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index bafb16a8b5e..34895d3efe6 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -602,6 +602,11 @@ impl UnordMap { .into_iter() .map(|(_, v)| v) } + + #[inline] + pub fn clear(&mut self) { + self.inner.clear() + } } impl Index<&Q> for UnordMap