diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 5490f1f53ea14..8f2fd9070bb14 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -678,11 +678,14 @@ impl<'tcx> Pat<'tcx> { | Binding { subpattern: None, .. } | Constant { .. } | Error(_) => {} + AscribeUserType { subpattern, .. } | Binding { subpattern: Some(subpattern), .. } | Deref { subpattern } | DerefPattern { subpattern, .. } - | ExpandedConstant { subpattern, .. } => subpattern.walk_(it), + | InlineConstMarker { subpattern, .. } + | NamedConstMarker { subpattern, .. } => subpattern.walk_(it), + Leaf { subpatterns } | Variant { subpatterns, .. } => { subpatterns.iter().for_each(|field| field.pattern.walk_(it)) } @@ -825,24 +828,29 @@ pub enum PatKind<'tcx> { value: mir::Const<'tcx>, }, - /// 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 - /// unevaluated constants and for diagnostics. If the `DefId` doesn't - /// correspond to a local crate, it points at the `const` item. + /// Marker node that wraps a pattern representing an inline-const block. + /// + /// THIR unsafeck uses this marker to discover inline-const blocks that + /// appear in patterns, so that they can be checked together with the rest + /// of their enclosing body. + /// + /// Note that if a range pattern has inline-const blocks for both endpoints, + /// the resulting THIR pattern will be an `InlineConstMarker`, containing + /// another `InlineConstMarker`, containing the underlying `Range` pattern. + InlineConstMarker { + /// ID of the inline-const block, for use by THIR unsafeck. + def_id: LocalDefId, + subpattern: Box<Pat<'tcx>>, + }, + + /// Marker node that wraps a pattern representing a named constant. + /// Enables better diagnostics in some cases, but has no other significance. + /// + /// (Even though this is superficially similar to `InlineConstMarker`, they + /// are very different in actual usage, so they should be kept separate.) + NamedConstMarker { + /// ID of the named constant, for use by diagnostics. 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). - /// - /// Otherwise, the actual pattern that the constant lowered to. As with - /// other constants, inline constants are matched structurally where - /// possible. subpattern: Box<Pat<'tcx>>, }, diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 2aeb13942a382..f2fc93848f0f3 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -243,7 +243,10 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( AscribeUserType { subpattern, ascription: _ } | Deref { subpattern } | DerefPattern { subpattern, .. } - | Binding { subpattern: Some(subpattern), .. } => visitor.visit_pat(subpattern), + | Binding { subpattern: Some(subpattern), .. } + | InlineConstMarker { subpattern, .. } + | NamedConstMarker { subpattern, .. } => visitor.visit_pat(subpattern), + Binding { .. } | Wild | Never | Error(_) => {} Variant { subpatterns, adt_def: _, args: _, variant_index: _ } | Leaf { subpatterns } => { for subpattern in subpatterns { @@ -251,7 +254,6 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( } } 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/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index eab414e150fa3..6d8244e490ed9 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -146,7 +146,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { let arm = &self.thir[*arm]; let value = match arm.pattern.kind { PatKind::Constant { value } => value, - PatKind::ExpandedConstant { ref subpattern, def_id: _, is_inline: false } + PatKind::NamedConstMarker { ref subpattern, def_id: _ } if let PatKind::Constant { value } = subpattern.kind => { value diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index 9d59ffc88ba23..95b37da722748 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -162,11 +162,11 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> { TestCase::Irrefutable { ascription: None, binding } } - PatKind::ExpandedConstant { subpattern: ref pattern, def_id: _, is_inline: false } => { + PatKind::NamedConstMarker { subpattern: ref pattern, def_id: _ } => { subpairs.push(MatchPairTree::for_pattern(place_builder, pattern, cx)); default_irrefutable() } - PatKind::ExpandedConstant { subpattern: ref pattern, def_id, is_inline: true } => { + PatKind::InlineConstMarker { subpattern: ref pattern, def_id } => { // Apply a type ascription for the inline constant to the value at `match_pair.place` let ascription = place.map(|source| { let span = pattern.span; @@ -177,7 +177,10 @@ impl<'pat, 'tcx> MatchPairTree<'pat, 'tcx> { }) .args; let user_ty = cx.infcx.canonicalize_user_type_annotation(ty::UserType::new( - ty::UserTypeKind::TypeOf(def_id, ty::UserArgs { args, user_self_ty: None }), + ty::UserTypeKind::TypeOf(def_id.to_def_id(), ty::UserArgs { + args, + user_self_ty: None, + }), )); let annotation = ty::CanonicalUserTypeAnnotation { inferred_ty: pattern.ty, diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index b21ec8f3083b3..0e7cfc04deaec 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -925,7 +925,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.visit_primary_bindings(subpattern, subpattern_user_ty, f) } - PatKind::ExpandedConstant { ref subpattern, .. } => { + PatKind::InlineConstMarker { ref subpattern, .. } + | PatKind::NamedConstMarker { 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 b6494173b0f08..45e3b610a6272 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -332,7 +332,8 @@ 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::ExpandedConstant { .. } | + PatKind::InlineConstMarker { .. } | + PatKind::NamedConstMarker { .. } | PatKind::AscribeUserType { .. } | PatKind::Error(_) => {} } @@ -400,12 +401,10 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { visit::walk_pat(self, pat); self.inside_adt = old_inside_adt; } - PatKind::ExpandedConstant { def_id, is_inline, .. } => { - if let Some(def) = def_id.as_local() - && *is_inline - { - self.visit_inner_body(def); - } + PatKind::InlineConstMarker { def_id, .. } => { + // Also visit the inline `const {}` block that this pattern + // represents. (See #116482 for context.) + self.visit_inner_body(*def_id); 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 8247a6c6a32d5..89e19d6e78997 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -676,10 +676,10 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { let mut interpreted_as_const = None; let mut interpreted_as_const_sugg = None; - if let PatKind::ExpandedConstant { def_id, is_inline: false, .. } + if let PatKind::NamedConstMarker { def_id, .. } | PatKind::AscribeUserType { subpattern: - box Pat { kind: PatKind::ExpandedConstant { def_id, is_inline: false, .. }, .. }, + box Pat { kind: PatKind::NamedConstMarker { def_id, .. }, .. }, .. } = pat.kind && let DefKind::Const = self.tcx.def_kind(def_id) @@ -1309,7 +1309,7 @@ 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::NamedConstMarker { def_id, .. } = 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 == '_') diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 0aa61152330a7..dd1c84a9d3e87 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -165,17 +165,23 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // deconstructed to obtain the constant value and other data. let mut kind: PatKind<'tcx> = self.lower_lit(expr); - // Unpeel any ascription or inline-const wrapper nodes. + // Unpeel any wrapper nodes, while preserving marker data that will + // need to be reapplied to the range pattern node. loop { match kind { PatKind::AscribeUserType { ascription, subpattern } => { ascriptions.push(ascription); kind = subpattern.kind; } - PatKind::ExpandedConstant { is_inline, def_id, subpattern } => { - if is_inline { - inline_consts.extend(def_id.as_local()); - } + PatKind::InlineConstMarker { def_id, subpattern } => { + // Preserve inline-const markers, so that THIR unsafeck can + // see const blocks that are part of a range pattern. + inline_consts.push(def_id); + kind = subpattern.kind; + } + PatKind::NamedConstMarker { subpattern, .. } => { + // Named-const markers are only used for improved diagnostics that + // aren't relevant to range patterns, so it's OK to discard them. kind = subpattern.kind; } _ => break, @@ -307,12 +313,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { subpattern: Box::new(Pat { span, ty, kind }), }; } - for def in inline_consts { - kind = PatKind::ExpandedConstant { - def_id: def.to_def_id(), - is_inline: true, - subpattern: Box::new(Pat { span, ty, kind }), - }; + // If one or both endpoints is an inline-const block, reapply the marker + // nodes so that unsafeck can traverse into the corresponding block body. + for def_id in inline_consts { + let subpattern = Box::new(Pat { span, ty, kind }); + kind = PatKind::InlineConstMarker { def_id, subpattern }; } Ok(kind) } @@ -593,11 +598,8 @@ 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 = Box::new(Pat { - span, - ty, - kind: PatKind::ExpandedConstant { subpattern, def_id, is_inline: false }, - }); + let pattern = + Box::new(Pat { span, ty, kind: PatKind::NamedConstMarker { subpattern, def_id } }); if !is_associated_const { return pattern; @@ -648,7 +650,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::ExpandedConstant { subpattern, def_id: def_id.to_def_id(), is_inline: true } + PatKind::InlineConstMarker { subpattern, def_id } } /// 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 729c8f784ba9f..11ad289bac5f1 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -733,10 +733,16 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, format!("value: {:?}", value), depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } - PatKind::ExpandedConstant { def_id, is_inline, subpattern } => { - print_indented!(self, "ExpandedConstant {", depth_lvl + 1); + PatKind::InlineConstMarker { def_id, subpattern } => { + print_indented!(self, "InlineConstMarker {", depth_lvl + 1); + print_indented!(self, format!("def_id: {def_id:?}"), depth_lvl + 2); + print_indented!(self, "subpattern:", depth_lvl + 2); + self.print_pat(subpattern, depth_lvl + 2); + print_indented!(self, "}", depth_lvl + 1); + } + PatKind::NamedConstMarker { def_id, subpattern } => { + print_indented!(self, "NamedConstMarker {", 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 2694cf472f480..e805d22f5d723 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -456,8 +456,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { let fields: Vec<_>; match &pat.kind { PatKind::AscribeUserType { subpattern, .. } - | PatKind::ExpandedConstant { subpattern, .. } => return self.lower_pat(subpattern), - PatKind::Binding { subpattern: Some(subpat), .. } => return self.lower_pat(subpat), + | PatKind::InlineConstMarker { subpattern, .. } + | PatKind::NamedConstMarker { subpattern, .. } + | PatKind::Binding { subpattern: Some(subpattern), .. } => { + return self.lower_pat(subpattern); + } + PatKind::Binding { subpattern: None, .. } | PatKind::Wild => { ctor = Wildcard; fields = vec![];