From 090747632dfd6a0748bb0b2e2d02de4af321ab84 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 16 Mar 2021 11:58:53 +0000 Subject: [PATCH 1/6] Add pretty printer support for `ConstValue` without going through ty::Const --- .../rustc_infer/src/infer/error_reporting/mod.rs | 9 +++++++++ compiler/rustc_lint/src/context.rs | 9 +++++++++ compiler/rustc_middle/src/ty/print/mod.rs | 15 +++++++++++++++ compiler/rustc_middle/src/ty/print/pretty.rs | 8 ++++++++ .../src/interpret/intrinsics/type_name.rs | 10 +++++++++- compiler/rustc_symbol_mangling/src/legacy.rs | 8 ++++++++ compiler/rustc_symbol_mangling/src/v0.rs | 9 +++++++++ 7 files changed, 67 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index e3a79fe265330..da7be40612a0a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -65,6 +65,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_hir::{Item, ItemKind, Node}; use rustc_middle::dep_graph::DepContext; +use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{ self, @@ -524,6 +525,14 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Err(NonTrivialPath) } + fn print_const_value( + self, + _value: ConstValue<'tcx>, + _ty: Ty<'tcx>, + ) -> Result { + Err(NonTrivialPath) + } + fn path_crate(self, cnum: CrateNum) -> Result { Ok(vec![self.tcx.crate_name(cnum).to_string()]) } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index c44df407f6b3a..43ac476cac722 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -31,6 +31,7 @@ use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; use rustc_middle::lint::LintDiagnosticBuilder; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::middle::stability; +use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty::layout::{LayoutError, TyAndLayout}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt}; @@ -943,6 +944,14 @@ impl<'tcx> LateContext<'tcx> { Ok(()) } + fn print_const_value( + self, + _val: ConstValue<'tcx>, + _ty: Ty<'tcx>, + ) -> Result { + Ok(()) + } + fn path_crate(self, cnum: CrateNum) -> Result { Ok(vec![self.tcx.crate_name(cnum)]) } diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 13e2122a619dc..2083f35ed1740 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -1,3 +1,4 @@ +use crate::mir::interpret::ConstValue; use crate::ty::subst::{GenericArg, Subst}; use crate::ty::{self, DefIdTree, Ty, TyCtxt}; @@ -68,6 +69,12 @@ pub trait Printer<'tcx>: Sized { fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result; + fn print_const_value( + self, + val: ConstValue<'tcx>, + ty: Ty<'tcx>, + ) -> Result; + fn path_crate(self, cnum: CrateNum) -> Result; fn path_qualified( @@ -362,3 +369,11 @@ impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for &'tcx ty::Const<'tcx> { cx.print_const(self) } } + +impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for (ConstValue<'tcx>, Ty<'tcx>) { + type Output = P::Const; + type Error = P::Error; + fn print(&self, cx: P) -> Result { + cx.print_const_value(self.0, self.1) + } +} diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index cb326996111b7..44fa4eb71d801 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1458,6 +1458,14 @@ impl Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { self.pretty_print_const(ct, true) } + fn print_const_value( + self, + val: ConstValue<'tcx>, + ty: Ty<'tcx>, + ) -> Result { + self.pretty_print_const_value(val, ty, true) + } + fn path_crate(mut self, cnum: CrateNum) -> Result { self.empty_path = true; if cnum == LOCAL_CRATE { diff --git a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs index a7012cd63f313..b1d7179cc8c6d 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs @@ -1,6 +1,6 @@ use rustc_hir::def_id::CrateNum; use rustc_hir::definitions::DisambiguatedDefPathData; -use rustc_middle::mir::interpret::Allocation; +use rustc_middle::mir::interpret::{Allocation, ConstValue}; use rustc_middle::ty::{ self, print::{PrettyPrinter, Print, Printer}, @@ -72,6 +72,14 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { self.pretty_print_const(ct, false) } + fn print_const_value( + self, + val: ConstValue<'tcx>, + ty: Ty<'tcx>, + ) -> Result { + self.pretty_print_const_value(val, ty, false) + } + fn print_dyn_existential( mut self, predicates: &'tcx ty::List>>, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 0c64fe6ea60a9..43732b98b46e1 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -253,6 +253,14 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { Ok(self) } + fn print_const_value( + self, + value: ConstValue<'tcx>, + ty: Ty<'tcx>, + ) -> Result { + bug!("symbol mangling should never see MIR constants, but saw {:?}:{:?}", value, ty) + } + fn path_crate(mut self, cnum: CrateNum) -> Result { self.write_str(&self.tcx.crate_name(cnum).as_str())?; Ok(self) diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 14442806fc0b7..bcc622551f768 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -3,6 +3,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; +use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::print::{Print, Printer}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; @@ -590,6 +591,14 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { Ok(self) } + fn print_const_value( + self, + value: ConstValue<'tcx>, + ty: Ty<'tcx>, + ) -> Result { + bug!("symbol mangling should never see MIR constants, but saw {:?}:{:?}", value, ty) + } + fn path_crate(mut self, cnum: CrateNum) -> Result { self.push("C"); let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id(); From 0502d429962d42a75a750aeb2a88b5216cbade6c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 16 Mar 2021 17:16:36 +0000 Subject: [PATCH 2/6] Add some convenience methods to `ScalarInt` --- compiler/rustc_middle/src/ty/consts/int.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index 8ed8ea6a0bc55..c8a507edae6f4 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -202,6 +202,23 @@ impl ScalarInt { Ok(Self::try_from_uint(f_int(u64::try_from(self.data).unwrap())?, self.size()).unwrap()) } + #[inline] + pub fn from_uint(i: impl Into, size: Size) -> Self { + let i = i.into(); + Self::try_from_uint(i, size) + .unwrap_or_else(|| bug!("Unsigned value {:#x} does not fit in {} bits", i, size.bits())) + } + + #[inline] + pub fn from_bool(b: bool) -> Self { + Self::from_uint(b as u8, Size::from_bytes(1)) + } + + #[inline] + pub fn from_char(c: char) -> Self { + Self::from_uint(c as u32, Size::from_bytes(4)) + } + #[inline] pub fn try_from_uint(i: impl Into, size: Size) -> Option { let data = i.into(); From aca10b380d25c606638d713084989ddadc01e188 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 17 Mar 2021 11:49:03 +0000 Subject: [PATCH 3/6] Simplify IntRange::from_const --- .../src/thir/pattern/deconstruct_pat.rs | 33 ++++++++----------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 4b5b648c5044f..925c555dbbea1 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -52,7 +52,6 @@ use rustc_data_structures::captures::Captures; use rustc_index::vec::Idx; use rustc_hir::{HirId, RangeEnd}; -use rustc_middle::mir::interpret::ConstValue; use rustc_middle::mir::Field; use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange}; use rustc_middle::ty::layout::IntegerExt; @@ -115,26 +114,20 @@ impl IntRange { param_env: ty::ParamEnv<'tcx>, value: &Const<'tcx>, ) -> Option { - if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, value.ty) { - let ty = value.ty; - let val = (|| { - if let ty::ConstKind::Value(ConstValue::Scalar(scalar)) = value.val { - // For this specific pattern we can skip a lot of effort and go - // straight to the result, after doing a bit of checking. (We - // could remove this branch and just fall through, which - // is more general but much slower.) - if let Ok(bits) = scalar.to_bits_or_ptr(target_size, &tcx) { - return Some(bits); - } - } - // This is a more general form of the previous case. - value.try_eval_bits(tcx, param_env, ty) - })()?; - let val = val ^ bias; - Some(IntRange { range: val..=val }) + let (target_size, bias) = Self::integral_size_and_signed_bias(tcx, value.ty)?; + let ty = value.ty; + let val = if let Some(int) = value.val.try_to_scalar_int() { + // For this specific pattern we can skip a lot of effort and go + // straight to the result, after doing a bit of checking. (We + // could remove this branch and just always use try_eval_bits, which + // is more general but much slower.) + int.assert_bits(target_size) } else { - None - } + // This is a more general form of the previous case. + value.try_eval_bits(tcx, param_env, ty)? + }; + let val = val ^ bias; + Some(IntRange { range: val..=val }) } #[inline] From 987b9fccdd40ef95fd9a5d40c15d03ba6d8d24f0 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 17 Mar 2021 13:01:34 +0000 Subject: [PATCH 4/6] Encode int/float/bool/char patterns directly as `ScalarInt` --- compiler/rustc_middle/src/thir.rs | 14 +++-- .../src/build/matches/simplify.rs | 28 ++++----- .../rustc_mir_build/src/build/matches/test.rs | 28 ++++++--- .../src/thir/pattern/deconstruct_pat.rs | 59 ++++++++++++++----- .../rustc_mir_build/src/thir/pattern/mod.rs | 21 ++++++- compiler/rustc_mir_build/src/thir/visit.rs | 5 +- ...ch_test.main.SimplifyCfg-initial.after.mir | 26 ++++---- .../ui/consts/const-match-check.eval1.stderr | 4 +- .../ui/consts/const-match-check.eval2.stderr | 4 +- .../consts/const-match-check.matchck.stderr | 16 ++--- .../ui/consts/const-pattern-irrefutable.rs | 6 +- .../consts/const-pattern-irrefutable.stderr | 6 +- ...oop-refutable-pattern-error-message.stderr | 4 +- ...alf-open-range-pats-exhaustive-fail.stderr | 44 +++++++------- .../exhaustiveness-non-exhaustive.rs | 6 +- .../exhaustiveness-non-exhaustive.stderr | 12 ++-- ...een-expanded-earlier-non-exhaustive.stderr | 8 +-- src/test/ui/pattern/usefulness/guards.stderr | 4 +- .../integer-ranges/exhaustiveness.stderr | 8 +-- .../match-byte-array-patterns-2.stderr | 4 +- .../usefulness/match-non-exhaustive.stderr | 4 +- .../usefulness/non-exhaustive-match.rs | 4 +- .../usefulness/non-exhaustive-match.stderr | 4 +- .../usefulness/refutable-pattern-errors.rs | 2 +- .../refutable-pattern-errors.stderr | 4 +- .../const-pat-non-exaustive-let-new-var.rs | 2 +- ...const-pat-non-exaustive-let-new-var.stderr | 2 +- 27 files changed, 193 insertions(+), 136 deletions(-) diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index cdefc9effa1e9..7766db5f468b1 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -26,6 +26,7 @@ use rustc_middle::ty::{self, AdtDef, Const, Ty, UpvarSubsts, UserType}; use rustc_middle::ty::{ CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, }; +use rustc_middle::ty::{ConstInt, ScalarInt}; use rustc_span::{Span, Symbol, DUMMY_SP}; use rustc_target::abi::VariantIdx; use rustc_target::asm::InlineAsmRegOrRegClass; @@ -668,8 +669,9 @@ pub enum PatKind<'tcx> { #[derive(Copy, Clone, Debug, PartialEq, HashStable)] pub struct PatRange<'tcx> { - pub lo: &'tcx ty::Const<'tcx>, - pub hi: &'tcx ty::Const<'tcx>, + pub lo: ScalarInt, + pub hi: ScalarInt, + pub ty: Ty<'tcx>, pub end: RangeEnd, } @@ -788,10 +790,12 @@ impl<'tcx> fmt::Display for Pat<'tcx> { write!(f, "{}", subpattern) } PatKind::Constant { value } => write!(f, "{}", value), - PatKind::Range(PatRange { lo, hi, end }) => { - write!(f, "{}", lo)?; + PatKind::Range(PatRange { lo, hi, end, ty }) => { + let lo = ConstInt::new(lo, ty.is_signed(), ty.is_ptr_sized_integral()); + let hi = ConstInt::new(hi, ty.is_signed(), ty.is_ptr_sized_integral()); + write!(f, "{:?}", lo)?; write!(f, "{}", end)?; - write!(f, "{}", hi) + write!(f, "{:?}", hi) } PatKind::Slice { ref prefix, ref slice, ref suffix } | PatKind::Array { ref prefix, ref slice, ref suffix } => { diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 13cfc3695cc9f..cde6d2c30182d 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -196,8 +196,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Err(match_pair) } - PatKind::Range(PatRange { lo, hi, end }) => { - let (range, bias) = match *lo.ty.kind() { + PatKind::Range(PatRange { lo, hi, end, ty }) => { + let (range, bias) = match *ty.kind() { ty::Char => { (Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0) } @@ -215,18 +215,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { _ => (None, 0), }; if let Some((min, max, sz)) = range { - if let (Some(lo), Some(hi)) = (lo.val.try_to_bits(sz), hi.val.try_to_bits(sz)) { - // We want to compare ranges numerically, but the order of the bitwise - // representation of signed integers does not match their numeric order. - // Thus, to correct the ordering, we need to shift the range of signed - // integers to correct the comparison. This is achieved by XORing with a - // bias (see pattern/_match.rs for another pertinent example of this - // pattern). - let (lo, hi) = (lo ^ bias, hi ^ bias); - if lo <= min && (hi > max || hi == max && end == RangeEnd::Included) { - // Irrefutable pattern match. - return Ok(()); - } + let lo = lo.assert_bits(sz); + let hi = hi.assert_bits(sz); + // We want to compare ranges numerically, but the order of the bitwise + // representation of signed integers does not match their numeric order. + // Thus, to correct the ordering, we need to shift the range of signed + // integers to correct the comparison. This is achieved by XORing with a + // bias (see pattern/_match.rs for another pertinent example of this + // pattern). + let (lo, hi) = (lo ^ bias, hi ^ bias); + if lo <= min && (hi > max || hi == max && end == RangeEnd::Included) { + // Irrefutable pattern match. + return Ok(()); } } Err(match_pair) diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index c87f42738c67f..2578562766af3 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -12,6 +12,7 @@ use crate::thir::pattern::compare_const_vals; use rustc_data_structures::fx::FxIndexMap; use rustc_hir::{LangItem, RangeEnd}; use rustc_index::bit_set::BitSet; +use rustc_middle::mir::interpret::ConstValue; use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty::subst::{GenericArg, Subst}; @@ -58,8 +59,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }, PatKind::Range(range) => { - assert_eq!(range.lo.ty, match_pair.pattern.ty); - assert_eq!(range.hi.ty, match_pair.pattern.ty); + assert_eq!(range.ty, match_pair.pattern.ty); Test { span: match_pair.pattern.span, kind: TestKind::Range(range) } } @@ -271,11 +271,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - TestKind::Range(PatRange { ref lo, ref hi, ref end }) => { + TestKind::Range(PatRange { lo, hi, ref end, ty }) => { let lower_bound_success = self.cfg.start_new_block(); let target_blocks = make_target_blocks(self); // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons. + let lo = ty::Const::from_value(self.tcx, ConstValue::Scalar(lo.into()), ty); + let hi = ty::Const::from_value(self.tcx, ConstValue::Scalar(hi.into()), ty); let lo = self.literal_operand(test.span, lo); let hi = self.literal_operand(test.span, hi); let val = Operand::Copy(place); @@ -640,9 +642,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let tcx = self.tcx; - let test_ty = test.lo.ty; - let lo = compare_const_vals(tcx, test.lo, pat.hi, self.param_env, test_ty)?; - let hi = compare_const_vals(tcx, test.hi, pat.lo, self.param_env, test_ty)?; + let test_ty = match_pair.pattern.ty; + let test_lo = + ty::Const::from_value(tcx, ConstValue::Scalar(test.lo.into()), test_ty); + let test_hi = + ty::Const::from_value(tcx, ConstValue::Scalar(test.hi.into()), test_ty); + let pat_lo = + ty::Const::from_value(tcx, ConstValue::Scalar(test.lo.into()), test_ty); + let pat_hi = + ty::Const::from_value(tcx, ConstValue::Scalar(test.hi.into()), test_ty); + let lo = compare_const_vals(tcx, test_lo, pat_hi, self.param_env, test_ty)?; + let hi = compare_const_vals(tcx, test_hi, pat_lo, self.param_env, test_ty)?; match (test.end, pat.end, lo, hi) { // pat < test @@ -769,8 +779,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let tcx = self.tcx; - let a = compare_const_vals(tcx, range.lo, value, self.param_env, range.lo.ty)?; - let b = compare_const_vals(tcx, value, range.hi, self.param_env, range.lo.ty)?; + let lo = ty::Const::from_value(tcx, ConstValue::Scalar(range.lo.into()), value.ty); + let hi = ty::Const::from_value(tcx, ConstValue::Scalar(range.hi.into()), value.ty); + let a = compare_const_vals(tcx, lo, value, self.param_env, value.ty)?; + let b = compare_const_vals(tcx, value, hi, self.param_env, value.ty)?; match (b, range.end) { (Less, _) | (Equal, RangeEnd::Included) if a != Greater => Some(true), diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 925c555dbbea1..a9492f02fe7f4 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -52,10 +52,11 @@ use rustc_data_structures::captures::Captures; use rustc_index::vec::Idx; use rustc_hir::{HirId, RangeEnd}; +use rustc_middle::mir::interpret::ConstValue; use rustc_middle::mir::Field; use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange}; use rustc_middle::ty::layout::IntegerExt; -use rustc_middle::ty::{self, Const, Ty, TyCtxt}; +use rustc_middle::ty::{self, Const, ScalarInt, Ty, TyCtxt}; use rustc_session::lint; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{Integer, Size, VariantIdx}; @@ -202,14 +203,18 @@ impl IntRange { let bias = IntRange::signed_bias(tcx, ty); let (lo, hi) = (lo ^ bias, hi ^ bias); - let env = ty::ParamEnv::empty().and(ty); - let lo_const = ty::Const::from_bits(tcx, lo, env); - let hi_const = ty::Const::from_bits(tcx, hi, env); - let kind = if lo == hi { - PatKind::Constant { value: lo_const } + let ty = ty::ParamEnv::empty().and(ty); + PatKind::Constant { value: ty::Const::from_bits(tcx, lo, ty) } } else { - PatKind::Range(PatRange { lo: lo_const, hi: hi_const, end: RangeEnd::Included }) + let param_env_and_ty = ty::ParamEnv::empty().and(ty); + let size = tcx.layout_of(param_env_and_ty).unwrap().size; + PatKind::Range(PatRange { + lo: ScalarInt::from_uint(lo, size), + hi: ScalarInt::from_uint(hi, size), + end: RangeEnd::Included, + ty, + }) }; Pat { ty, span: DUMMY_SP, kind: Box::new(kind) } @@ -586,7 +591,7 @@ pub(super) enum Constructor<'tcx> { /// Ranges of integer literal values (`2`, `2..=5` or `2..5`). IntRange(IntRange), /// Ranges of floating-point literal values (`2.0..=5.2`). - FloatRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd), + FloatRange(ScalarInt, ScalarInt, RangeEnd), /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately. Str(&'tcx ty::Const<'tcx>), /// Array and slice patterns. @@ -647,7 +652,11 @@ impl<'tcx> Constructor<'tcx> { IntRange(int_range) } else { match pat.ty.kind() { - ty::Float(_) => FloatRange(value, value, RangeEnd::Included), + ty::Float(_) => { + let value = + value.val.eval(cx.tcx, cx.param_env).try_to_scalar_int().unwrap(); + FloatRange(value, value, RangeEnd::Included) + } // In `expand_pattern`, we convert string literals to `&CONST` patterns with // `CONST` a pattern of type `str`. In truth this contains a constant of type // `&str`. @@ -659,13 +668,13 @@ impl<'tcx> Constructor<'tcx> { } } } - &PatKind::Range(PatRange { lo, hi, end }) => { - let ty = lo.ty; + &PatKind::Range(PatRange { lo, hi, end, ty }) => { + let size = cx.tcx.layout_of(cx.param_env.and(ty)).unwrap().size; if let Some(int_range) = IntRange::from_range( cx.tcx, - lo.eval_bits(cx.tcx, cx.param_env, lo.ty), - hi.eval_bits(cx.tcx, cx.param_env, hi.ty), - ty, + lo.assert_bits(size), + hi.assert_bits(size), + pat.ty, &end, ) { IntRange(int_range) @@ -759,6 +768,26 @@ impl<'tcx> Constructor<'tcx> { FloatRange(self_from, self_to, self_end), FloatRange(other_from, other_to, other_end), ) => { + let self_to = ty::Const::from_value( + pcx.cx.tcx, + ConstValue::Scalar((*self_to).into()), + pcx.ty, + ); + let other_to = ty::Const::from_value( + pcx.cx.tcx, + ConstValue::Scalar((*other_to).into()), + pcx.ty, + ); + let self_from = ty::Const::from_value( + pcx.cx.tcx, + ConstValue::Scalar((*self_from).into()), + pcx.ty, + ); + let other_from = ty::Const::from_value( + pcx.cx.tcx, + ConstValue::Scalar((*other_from).into()), + pcx.ty, + ); match ( compare_const_vals(pcx.cx.tcx, self_to, other_to, pcx.cx.param_env, pcx.ty), compare_const_vals(pcx.cx.tcx, self_from, other_from, pcx.cx.param_env, pcx.ty), @@ -1253,7 +1282,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { } }, &Str(value) => PatKind::Constant { value }, - &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end }), + &FloatRange(lo, hi, end) => PatKind::Range(PatRange { lo, hi, end, ty: pcx.ty }), IntRange(range) => return range.to_pat(pcx.cx.tcx, pcx.ty), NonExhaustive => PatKind::Wild, Wildcard => return Pat::wildcard_from_ty(pcx.ty), diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 3ea76fb99d531..081ff09f59e91 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -130,10 +130,23 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { assert_eq!(lo.ty, ty); assert_eq!(hi.ty, ty); let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env, ty); + let lo_const = lo; + let lo = lo + .val + .eval(self.tcx, self.param_env) + .try_to_scalar_int() + .expect("range patterns must be integral"); + let hi = hi + .val + .eval(self.tcx, self.param_env) + .try_to_scalar_int() + .expect("range patterns must be integral"); match (end, cmp) { // `x..y` where `x < y`. // Non-empty because the range includes at least `x`. - (RangeEnd::Excluded, Some(Ordering::Less)) => PatKind::Range(PatRange { lo, hi, end }), + (RangeEnd::Excluded, Some(Ordering::Less)) => { + PatKind::Range(PatRange { lo, hi, end, ty }) + } // `x..y` where `x >= y`. The range is empty => error. (RangeEnd::Excluded, _) => { struct_span_err!( @@ -146,9 +159,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { PatKind::Wild } // `x..=y` where `x == y`. - (RangeEnd::Included, Some(Ordering::Equal)) => PatKind::Constant { value: lo }, + (RangeEnd::Included, Some(Ordering::Equal)) => PatKind::Constant { value: lo_const }, // `x..=y` where `x < y`. - (RangeEnd::Included, Some(Ordering::Less)) => PatKind::Range(PatRange { lo, hi, end }), + (RangeEnd::Included, Some(Ordering::Less)) => { + PatKind::Range(PatRange { lo, hi, end, ty }) + } // `x..=y` where `x > y` hence the range is empty => error. (RangeEnd::Included, _) => { let mut err = struct_span_err!( diff --git a/compiler/rustc_mir_build/src/thir/visit.rs b/compiler/rustc_mir_build/src/thir/visit.rs index f611bb6eb43e9..6f699b8c8d910 100644 --- a/compiler/rustc_mir_build/src/thir/visit.rs +++ b/compiler/rustc_mir_build/src/thir/visit.rs @@ -213,10 +213,7 @@ pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<' } } Constant { value } => visitor.visit_const(value), - Range(range) => { - visitor.visit_const(range.lo); - visitor.visit_const(range.hi); - } + Range(PatRange { lo: _, hi: _, ty: _, end: _ }) => {} Slice { prefix, slice, suffix } | Array { prefix, slice, suffix } => { for subpattern in prefix { visitor.visit_pat(&subpattern); diff --git a/src/test/mir-opt/match_test.main.SimplifyCfg-initial.after.mir b/src/test/mir-opt/match_test.main.SimplifyCfg-initial.after.mir index 5bb910947ca25..e050b5ea0b4ee 100644 --- a/src/test/mir-opt/match_test.main.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/match_test.main.SimplifyCfg-initial.after.mir @@ -28,43 +28,43 @@ fn main() -> () { StorageLive(_3); // scope 2 at $DIR/match_test.rs:12:5: 17:6 FakeRead(ForMatchedPlace(None), _1); // scope 2 at $DIR/match_test.rs:12:11: 12:12 _6 = Le(const 0_i32, _1); // scope 2 at $DIR/match_test.rs:13:9: 13:14 - switchInt(move _6) -> [false: bb4, otherwise: bb1]; // scope 2 at $DIR/match_test.rs:13:9: 13:14 + switchInt(move _6) -> [false: bb3, otherwise: bb1]; // scope 2 at $DIR/match_test.rs:13:9: 13:14 } bb1: { _7 = Lt(_1, const 10_i32); // scope 2 at $DIR/match_test.rs:13:9: 13:14 - switchInt(move _7) -> [false: bb4, otherwise: bb2]; // scope 2 at $DIR/match_test.rs:13:9: 13:14 + switchInt(move _7) -> [false: bb3, otherwise: bb2]; // scope 2 at $DIR/match_test.rs:13:9: 13:14 } bb2: { - falseEdge -> [real: bb9, imaginary: bb6]; // scope 2 at $DIR/match_test.rs:13:9: 13:14 + falseEdge -> [real: bb9, imaginary: bb5]; // scope 2 at $DIR/match_test.rs:13:9: 13:14 } bb3: { - _3 = const 3_i32; // scope 2 at $DIR/match_test.rs:16:14: 16:15 - goto -> bb14; // scope 2 at $DIR/match_test.rs:12:5: 17:6 + _4 = Le(const 10_i32, _1); // scope 2 at $DIR/match_test.rs:14:9: 14:16 + switchInt(move _4) -> [false: bb6, otherwise: bb4]; // scope 2 at $DIR/match_test.rs:14:9: 14:16 } bb4: { - _4 = Le(const 10_i32, _1); // scope 2 at $DIR/match_test.rs:14:9: 14:16 - switchInt(move _4) -> [false: bb7, otherwise: bb5]; // scope 2 at $DIR/match_test.rs:14:9: 14:16 + _5 = Le(_1, const 20_i32); // scope 2 at $DIR/match_test.rs:14:9: 14:16 + switchInt(move _5) -> [false: bb6, otherwise: bb5]; // scope 2 at $DIR/match_test.rs:14:9: 14:16 } bb5: { - _5 = Le(_1, const 20_i32); // scope 2 at $DIR/match_test.rs:14:9: 14:16 - switchInt(move _5) -> [false: bb7, otherwise: bb6]; // scope 2 at $DIR/match_test.rs:14:9: 14:16 + falseEdge -> [real: bb12, imaginary: bb7]; // scope 2 at $DIR/match_test.rs:14:9: 14:16 } bb6: { - falseEdge -> [real: bb12, imaginary: bb8]; // scope 2 at $DIR/match_test.rs:14:9: 14:16 + switchInt(_1) -> [-1_i32: bb7, otherwise: bb8]; // scope 2 at $DIR/match_test.rs:15:9: 15:11 } bb7: { - switchInt(_1) -> [-1_i32: bb8, otherwise: bb3]; // scope 2 at $DIR/match_test.rs:15:9: 15:11 + falseEdge -> [real: bb13, imaginary: bb8]; // scope 2 at $DIR/match_test.rs:15:9: 15:11 } bb8: { - falseEdge -> [real: bb13, imaginary: bb3]; // scope 2 at $DIR/match_test.rs:15:9: 15:11 + _3 = const 3_i32; // scope 2 at $DIR/match_test.rs:16:14: 16:15 + goto -> bb14; // scope 2 at $DIR/match_test.rs:12:5: 17:6 } bb9: { @@ -83,7 +83,7 @@ fn main() -> () { bb11: { StorageDead(_9); // scope 2 at $DIR/match_test.rs:13:23: 13:24 - falseEdge -> [real: bb3, imaginary: bb6]; // scope 2 at $DIR/match_test.rs:13:18: 13:19 + falseEdge -> [real: bb3, imaginary: bb5]; // scope 2 at $DIR/match_test.rs:13:18: 13:19 } bb12: { diff --git a/src/test/ui/consts/const-match-check.eval1.stderr b/src/test/ui/consts/const-match-check.eval1.stderr index eb6b0774e152c..2194b3f1b0363 100644 --- a/src/test/ui/consts/const-match-check.eval1.stderr +++ b/src/test/ui/consts/const-match-check.eval1.stderr @@ -1,8 +1,8 @@ -error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered +error[E0005]: refutable pattern in local binding: `i32::MIN..=-1` and `1..=i32::MAX` not covered --> $DIR/const-match-check.rs:25:15 | LL | A = { let 0 = 0; 0 }, - | ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered + | ^ patterns `i32::MIN..=-1` and `1..=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 diff --git a/src/test/ui/consts/const-match-check.eval2.stderr b/src/test/ui/consts/const-match-check.eval2.stderr index 756426d84a479..e4844feec28d3 100644 --- a/src/test/ui/consts/const-match-check.eval2.stderr +++ b/src/test/ui/consts/const-match-check.eval2.stderr @@ -1,8 +1,8 @@ -error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered +error[E0005]: refutable pattern in local binding: `i32::MIN..=-1` and `1..=i32::MAX` not covered --> $DIR/const-match-check.rs:31:24 | LL | let x: [i32; { let 0 = 0; 0 }] = []; - | ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered + | ^ patterns `i32::MIN..=-1` and `1..=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 diff --git a/src/test/ui/consts/const-match-check.matchck.stderr b/src/test/ui/consts/const-match-check.matchck.stderr index 84600bb1b8aad..9e5cc99bcf9d6 100644 --- a/src/test/ui/consts/const-match-check.matchck.stderr +++ b/src/test/ui/consts/const-match-check.matchck.stderr @@ -1,8 +1,8 @@ -error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered +error[E0005]: refutable pattern in local binding: `i32::MIN..=-1` and `1..=i32::MAX` not covered --> $DIR/const-match-check.rs:4:22 | LL | const X: i32 = { let 0 = 0; 0 }; - | ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered + | ^ patterns `i32::MIN..=-1` and `1..=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 @@ -12,11 +12,11 @@ help: you might want to use `if let` to ignore the variant that isn't matched LL | const X: i32 = { if let 0 = 0 { /* */ } 0 }; | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered +error[E0005]: refutable pattern in local binding: `i32::MIN..=-1` and `1..=i32::MAX` not covered --> $DIR/const-match-check.rs:8:23 | LL | static Y: i32 = { let 0 = 0; 0 }; - | ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered + | ^ patterns `i32::MIN..=-1` and `1..=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 @@ -26,11 +26,11 @@ help: you might want to use `if let` to ignore the variant that isn't matched LL | static Y: i32 = { if let 0 = 0 { /* */ } 0 }; | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered +error[E0005]: refutable pattern in local binding: `i32::MIN..=-1` and `1..=i32::MAX` not covered --> $DIR/const-match-check.rs:13:26 | LL | const X: i32 = { let 0 = 0; 0 }; - | ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered + | ^ patterns `i32::MIN..=-1` and `1..=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 @@ -40,11 +40,11 @@ help: you might want to use `if let` to ignore the variant that isn't matched LL | const X: i32 = { if let 0 = 0 { /* */ } 0 }; | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered +error[E0005]: refutable pattern in local binding: `i32::MIN..=-1` and `1..=i32::MAX` not covered --> $DIR/const-match-check.rs:19:26 | LL | const X: i32 = { let 0 = 0; 0 }; - | ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered + | ^ patterns `i32::MIN..=-1` and `1..=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 diff --git a/src/test/ui/consts/const-pattern-irrefutable.rs b/src/test/ui/consts/const-pattern-irrefutable.rs index 2105c12a1680a..593ebfbec07c2 100644 --- a/src/test/ui/consts/const-pattern-irrefutable.rs +++ b/src/test/ui/consts/const-pattern-irrefutable.rs @@ -9,8 +9,8 @@ use foo::d; const a: u8 = 2; fn main() { - let a = 4; //~ ERROR refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX - let c = 4; //~ ERROR refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX - let d = 4; //~ ERROR refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX + let a = 4; //~ ERROR refutable pattern in local binding: `0..=1` and `3..=u8::MAX + let c = 4; //~ ERROR refutable pattern in local binding: `0..=1` and `3..=u8::MAX + let d = 4; //~ ERROR refutable pattern in local binding: `0..=1` and `3..=u8::MAX fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115). } diff --git a/src/test/ui/consts/const-pattern-irrefutable.stderr b/src/test/ui/consts/const-pattern-irrefutable.stderr index 3e3bc1979a2e0..ff5e478e991c8 100644 --- a/src/test/ui/consts/const-pattern-irrefutable.stderr +++ b/src/test/ui/consts/const-pattern-irrefutable.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered +error[E0005]: refutable pattern in local binding: `0..=1` and `3..=u8::MAX` not covered --> $DIR/const-pattern-irrefutable.rs:12:9 | LL | const a: u8 = 2; @@ -12,7 +12,7 @@ LL | let a = 4; | = note: the matched value is of type `u8` -error[E0005]: refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered +error[E0005]: refutable pattern in local binding: `0..=1` and `3..=u8::MAX` not covered --> $DIR/const-pattern-irrefutable.rs:13:9 | LL | pub const b: u8 = 2; @@ -26,7 +26,7 @@ LL | let c = 4; | = note: the matched value is of type `u8` -error[E0005]: refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered +error[E0005]: refutable pattern in local binding: `0..=1` and `3..=u8::MAX` not covered --> $DIR/const-pattern-irrefutable.rs:14:9 | LL | pub const d: u8 = 2; diff --git a/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr b/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr index 20b689aa5e0af..bd662549b1e1c 100644 --- a/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr +++ b/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr @@ -1,8 +1,8 @@ -error[E0005]: refutable pattern in `for` loop binding: `&i32::MIN..=0_i32` and `&2_i32..=i32::MAX` not covered +error[E0005]: refutable pattern in `for` loop binding: `&i32::MIN..=0` and `&2..=i32::MAX` not covered --> $DIR/for-loop-refutable-pattern-error-message.rs:2:9 | LL | for &1 in [1].iter() {} - | ^^ patterns `&i32::MIN..=0_i32` and `&2_i32..=i32::MAX` not covered + | ^^ patterns `&i32::MIN..=0` and `&2..=i32::MAX` not covered | = note: the matched value is of type `&i32` diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr b/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr index 14dbca60b78f2..6ec0f7702efc4 100644 --- a/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr +++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-exhaustive-fail.stderr @@ -25,11 +25,11 @@ LL | m!('a', ..core::char::MAX); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `char` -error[E0004]: non-exhaustive patterns: `'\u{10fffe}'..='\u{10ffff}'` not covered +error[E0004]: non-exhaustive patterns: `1114110..=1114111` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:27:8 | LL | m!('a', ..ALMOST_MAX); - | ^^^ pattern `'\u{10fffe}'..='\u{10ffff}'` not covered + | ^^^ pattern `1114110..=1114111` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `char` @@ -79,11 +79,11 @@ LL | m!(0, ..u8::MAX); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u8` -error[E0004]: non-exhaustive patterns: `254_u8..=u8::MAX` not covered +error[E0004]: non-exhaustive patterns: `254..=u8::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:42:12 | LL | m!(0, ..ALMOST_MAX); - | ^ pattern `254_u8..=u8::MAX` not covered + | ^ pattern `254..=u8::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u8` @@ -133,11 +133,11 @@ LL | m!(0, ..u16::MAX); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u16` -error[E0004]: non-exhaustive patterns: `65534_u16..=u16::MAX` not covered +error[E0004]: non-exhaustive patterns: `65534..=u16::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:55:12 | LL | m!(0, ..ALMOST_MAX); - | ^ pattern `65534_u16..=u16::MAX` not covered + | ^ pattern `65534..=u16::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u16` @@ -187,11 +187,11 @@ LL | m!(0, ..u32::MAX); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u32` -error[E0004]: non-exhaustive patterns: `4294967294_u32..=u32::MAX` not covered +error[E0004]: non-exhaustive patterns: `4294967294..=u32::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:68:12 | LL | m!(0, ..ALMOST_MAX); - | ^ pattern `4294967294_u32..=u32::MAX` not covered + | ^ pattern `4294967294..=u32::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u32` @@ -241,11 +241,11 @@ LL | m!(0, ..u64::MAX); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u64` -error[E0004]: non-exhaustive patterns: `18446744073709551614_u64..=u64::MAX` not covered +error[E0004]: non-exhaustive patterns: `18446744073709551614..=u64::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:81:12 | LL | m!(0, ..ALMOST_MAX); - | ^ pattern `18446744073709551614_u64..=u64::MAX` not covered + | ^ pattern `18446744073709551614..=u64::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u64` @@ -295,11 +295,11 @@ LL | m!(0, ..u128::MAX); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u128` -error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454_u128..=u128::MAX` not covered +error[E0004]: non-exhaustive patterns: `340282366920938463463374607431768211454..=u128::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:94:12 | LL | m!(0, ..ALMOST_MAX); - | ^ pattern `340282366920938463463374607431768211454_u128..=u128::MAX` not covered + | ^ pattern `340282366920938463463374607431768211454..=u128::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u128` @@ -349,11 +349,11 @@ LL | m!(0, ..i8::MAX); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i8` -error[E0004]: non-exhaustive patterns: `126_i8..=i8::MAX` not covered +error[E0004]: non-exhaustive patterns: `126..=i8::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:110:12 | LL | m!(0, ..ALMOST_MAX); - | ^ pattern `126_i8..=i8::MAX` not covered + | ^ pattern `126..=i8::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i8` @@ -403,11 +403,11 @@ LL | m!(0, ..i16::MAX); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i16` -error[E0004]: non-exhaustive patterns: `32766_i16..=i16::MAX` not covered +error[E0004]: non-exhaustive patterns: `32766..=i16::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:123:12 | LL | m!(0, ..ALMOST_MAX); - | ^ pattern `32766_i16..=i16::MAX` not covered + | ^ pattern `32766..=i16::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i16` @@ -457,11 +457,11 @@ LL | m!(0, ..i32::MAX); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i32` -error[E0004]: non-exhaustive patterns: `2147483646_i32..=i32::MAX` not covered +error[E0004]: non-exhaustive patterns: `2147483646..=i32::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:136:12 | LL | m!(0, ..ALMOST_MAX); - | ^ pattern `2147483646_i32..=i32::MAX` not covered + | ^ pattern `2147483646..=i32::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i32` @@ -511,11 +511,11 @@ LL | m!(0, ..i64::MAX); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i64` -error[E0004]: non-exhaustive patterns: `9223372036854775806_i64..=i64::MAX` not covered +error[E0004]: non-exhaustive patterns: `9223372036854775806..=i64::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:149:12 | LL | m!(0, ..ALMOST_MAX); - | ^ pattern `9223372036854775806_i64..=i64::MAX` not covered + | ^ pattern `9223372036854775806..=i64::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i64` @@ -565,11 +565,11 @@ LL | m!(0, ..i128::MAX); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i128` -error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726_i128..=i128::MAX` not covered +error[E0004]: non-exhaustive patterns: `170141183460469231731687303715884105726..=i128::MAX` not covered --> $DIR/half-open-range-pats-exhaustive-fail.rs:162:12 | LL | m!(0, ..ALMOST_MAX); - | ^ pattern `170141183460469231731687303715884105726_i128..=i128::MAX` not covered + | ^ pattern `170141183460469231731687303715884105726..=i128::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i128` diff --git a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs index 5999e04e0e2dd..037423e39c5f3 100644 --- a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs +++ b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.rs @@ -3,15 +3,15 @@ // We wrap patterns in a tuple because top-level or-patterns were special-cased. fn main() { match (0u8, 0u8) { - //~^ ERROR non-exhaustive patterns: `(2_u8..=u8::MAX, _)` + //~^ ERROR non-exhaustive patterns: `(2..=u8::MAX, _)` (0 | 1, 2 | 3) => {} } match ((0u8,),) { - //~^ ERROR non-exhaustive patterns: `((4_u8..=u8::MAX))` + //~^ ERROR non-exhaustive patterns: `((4..=u8::MAX))` ((0 | 1,) | (2 | 3,),) => {} } match (Some(0u8),) { - //~^ ERROR non-exhaustive patterns: `(Some(2_u8..=u8::MAX))` + //~^ ERROR non-exhaustive patterns: `(Some(2..=u8::MAX))` (None | Some(0 | 1),) => {} } } diff --git a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr index 44f334eee9386..b2d81fdb52281 100644 --- a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr +++ b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr @@ -1,26 +1,26 @@ -error[E0004]: non-exhaustive patterns: `(2_u8..=u8::MAX, _)` not covered +error[E0004]: non-exhaustive patterns: `(2..=u8::MAX, _)` not covered --> $DIR/exhaustiveness-non-exhaustive.rs:5:11 | LL | match (0u8, 0u8) { - | ^^^^^^^^^^ pattern `(2_u8..=u8::MAX, _)` not covered + | ^^^^^^^^^^ pattern `(2..=u8::MAX, _)` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `(u8, u8)` -error[E0004]: non-exhaustive patterns: `((4_u8..=u8::MAX))` not covered +error[E0004]: non-exhaustive patterns: `((4..=u8::MAX))` not covered --> $DIR/exhaustiveness-non-exhaustive.rs:9:11 | LL | match ((0u8,),) { - | ^^^^^^^^^ pattern `((4_u8..=u8::MAX))` not covered + | ^^^^^^^^^ pattern `((4..=u8::MAX))` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `((u8,),)` -error[E0004]: non-exhaustive patterns: `(Some(2_u8..=u8::MAX))` not covered +error[E0004]: non-exhaustive patterns: `(Some(2..=u8::MAX))` not covered --> $DIR/exhaustiveness-non-exhaustive.rs:13:11 | LL | match (Some(0u8),) { - | ^^^^^^^^^^^^ pattern `(Some(2_u8..=u8::MAX))` not covered + | ^^^^^^^^^^^^ pattern `(Some(2..=u8::MAX))` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `(Option,)` diff --git a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr index 61175b84ee1de..8355959c249e4 100644 --- a/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr +++ b/src/test/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr @@ -1,8 +1,8 @@ -error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered +error[E0005]: refutable pattern in local binding: `i32::MIN..=-1` and `3..=i32::MAX` not covered --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:2:10 | LL | let (0 | (1 | 2)) = 0; - | ^^^^^^^^^^^ patterns `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered + | ^^^^^^^^^^^ patterns `i32::MIN..=-1` and `3..=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 @@ -12,11 +12,11 @@ help: you might want to use `if let` to ignore the variant that isn't matched LL | if let (0 | (1 | 2)) = 0 { /* */ } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0004]: non-exhaustive patterns: `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered +error[E0004]: non-exhaustive patterns: `i32::MIN..=-1` and `3..=i32::MAX` not covered --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:3:11 | LL | match 0 { - | ^ patterns `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered + | ^ patterns `i32::MIN..=-1` and `3..=i32::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i32` diff --git a/src/test/ui/pattern/usefulness/guards.stderr b/src/test/ui/pattern/usefulness/guards.stderr index 61f7facb330da..7a5fd66ce003d 100644 --- a/src/test/ui/pattern/usefulness/guards.stderr +++ b/src/test/ui/pattern/usefulness/guards.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `128_u8..=u8::MAX` not covered +error[E0004]: non-exhaustive patterns: `128..=u8::MAX` not covered --> $DIR/guards.rs:12:11 | LL | match 0u8 { - | ^^^ pattern `128_u8..=u8::MAX` not covered + | ^^^ pattern `128..=u8::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u8` diff --git a/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr b/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr index b1440375494b1..48dabdcc2bca5 100644 --- a/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr +++ b/src/test/ui/pattern/usefulness/integer-ranges/exhaustiveness.stderr @@ -79,11 +79,11 @@ LL | m!(0u128, 0..=ALMOST_MAX); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u128` -error[E0004]: non-exhaustive patterns: `5_u128..=u128::MAX` not covered +error[E0004]: non-exhaustive patterns: `5..=u128::MAX` not covered --> $DIR/exhaustiveness.rs:61:8 | LL | m!(0u128, 0..=4); - | ^^^^^ pattern `5_u128..=u128::MAX` not covered + | ^^^^^ pattern `5..=u128::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u128` @@ -97,11 +97,11 @@ LL | m!(0u128, 1..=u128::MAX); = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `u128` -error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered +error[E0004]: non-exhaustive patterns: `(126..=127, false)` not covered --> $DIR/exhaustiveness.rs:70:11 | LL | match (0u8, true) { - | ^^^^^^^^^^^ pattern `(126_u8..=127_u8, false)` not covered + | ^^^^^^^^^^^ pattern `(126..=127, false)` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `(u8, bool)` diff --git a/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr b/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr index ffc8433403fd5..95187fa0b35d0 100644 --- a/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr +++ b/src/test/ui/pattern/usefulness/match-byte-array-patterns-2.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered +error[E0004]: non-exhaustive patterns: `&[0..=64, _, _, _]` and `&[66..=u8::MAX, _, _, _]` not covered --> $DIR/match-byte-array-patterns-2.rs:4:11 | LL | match buf { - | ^^^ patterns `&[0_u8..=64_u8, _, _, _]` and `&[66_u8..=u8::MAX, _, _, _]` not covered + | ^^^ patterns `&[0..=64, _, _, _]` and `&[66..=u8::MAX, _, _, _]` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `&[u8; 4]` diff --git a/src/test/ui/pattern/usefulness/match-non-exhaustive.stderr b/src/test/ui/pattern/usefulness/match-non-exhaustive.stderr index a35d61e4b710b..cbfe3a5e97489 100644 --- a/src/test/ui/pattern/usefulness/match-non-exhaustive.stderr +++ b/src/test/ui/pattern/usefulness/match-non-exhaustive.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `i32::MIN..=0_i32` and `2_i32..=i32::MAX` not covered +error[E0004]: non-exhaustive patterns: `i32::MIN..=0` and `2..=i32::MAX` not covered --> $DIR/match-non-exhaustive.rs:2:11 | LL | match 0 { 1 => () } - | ^ patterns `i32::MIN..=0_i32` and `2_i32..=i32::MAX` not covered + | ^ patterns `i32::MIN..=0` and `2..=i32::MAX` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `i32` diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.rs b/src/test/ui/pattern/usefulness/non-exhaustive-match.rs index 4ff12aa2ff5e2..af9513874b44a 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-match.rs +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.rs @@ -11,8 +11,8 @@ fn main() { match Some(10) { //~ ERROR non-exhaustive patterns: `Some(_)` not covered None => {} } - match (2, 3, 4) { //~ ERROR non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)` - // and `(_, _, 5_i32..=i32::MAX)` not covered + match (2, 3, 4) { //~ ERROR non-exhaustive patterns: `(_, _, i32::MIN..=3)` + // and `(_, _, 5..=i32::MAX)` not covered (_, _, 4) => {} } match (T::A, T::A) { //~ ERROR non-exhaustive patterns: `(A, A)` and `(B, B)` not covered diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr index c953cd314406e..c29637d74a9ba 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr @@ -36,11 +36,11 @@ LL | Some(#[stable(feature = "rust1", since = "1.0.0")] T), = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `Option` -error[E0004]: non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered +error[E0004]: non-exhaustive patterns: `(_, _, i32::MIN..=3)` and `(_, _, 5..=i32::MAX)` not covered --> $DIR/non-exhaustive-match.rs:14:11 | LL | match (2, 3, 4) { - | ^^^^^^^^^ patterns `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered + | ^^^^^^^^^ patterns `(_, _, i32::MIN..=3)` and `(_, _, 5..=i32::MAX)` not covered | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `(i32, i32, i32)` diff --git a/src/test/ui/pattern/usefulness/refutable-pattern-errors.rs b/src/test/ui/pattern/usefulness/refutable-pattern-errors.rs index 7c9aa51e7484c..cc0a0abd10c69 100644 --- a/src/test/ui/pattern/usefulness/refutable-pattern-errors.rs +++ b/src/test/ui/pattern/usefulness/refutable-pattern-errors.rs @@ -3,5 +3,5 @@ fn func((1, (Some(1), 2..=3)): (isize, (Option, isize))) { } fn main() { let (1, (Some(1), 2..=3)) = (1, (None, 2)); - //~^ ERROR refutable pattern in local binding: `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered + //~^ ERROR refutable pattern in local binding: `(i32::MIN..=0, _)` and `(2..=i32::MAX, _)` not covered } diff --git a/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr b/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr index 74ec646e31cca..027371936d3c9 100644 --- a/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr +++ b/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr @@ -6,11 +6,11 @@ LL | fn func((1, (Some(1), 2..=3)): (isize, (Option, isize))) { } | = note: the matched value is of type `(isize, (Option, isize))` -error[E0005]: refutable pattern in local binding: `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered +error[E0005]: refutable pattern in local binding: `(i32::MIN..=0, _)` and `(2..=i32::MAX, _)` not covered --> $DIR/refutable-pattern-errors.rs:5:9 | LL | let (1, (Some(1), 2..=3)) = (1, (None, 2)); - | ^^^^^^^^^^^^^^^^^^^^^ patterns `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered + | ^^^^^^^^^^^^^^^^^^^^^ patterns `(i32::MIN..=0, _)` and `(2..=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 diff --git a/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.rs b/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.rs index ac819dce6db2b..53fd5a5e3a51f 100644 --- a/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.rs +++ b/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.rs @@ -1,6 +1,6 @@ fn main() { let A = 3; - //~^ ERROR refutable pattern in local binding: `i32::MIN..=1_i32` and + //~^ ERROR refutable pattern in local binding: `i32::MIN..=1` and //~| interpreted as a constant pattern, not a new variable //~| HELP introduce a variable instead //~| SUGGESTION a_var diff --git a/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr b/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr index af64c09d5cadb..bfff3d3b8ec06 100644 --- a/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr +++ b/src/test/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr @@ -1,4 +1,4 @@ -error[E0005]: refutable pattern in local binding: `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered +error[E0005]: refutable pattern in local binding: `i32::MIN..=1` and `3..=i32::MAX` not covered --> $DIR/const-pat-non-exaustive-let-new-var.rs:2:9 | LL | let A = 3; From b2a2286f0068aa5fe557213ce665a434677bdd63 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 17 Mar 2021 13:51:14 +0000 Subject: [PATCH 5/6] Use ScalarInt as early as possible... ...instead of carrying around ty::Const and erroring later --- compiler/rustc_middle/src/ty/util.rs | 32 ++++++------- .../rustc_mir_build/src/thir/pattern/mod.rs | 33 +++++-------- .../clippy/clippy_lints/src/enum_clike.rs | 6 +-- src/tools/clippy/clippy_lints/src/matches.rs | 11 ++++- src/tools/clippy/clippy_utils/src/consts.rs | 48 ++++++++----------- 5 files changed, 61 insertions(+), 69 deletions(-) diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 485be4c9987bd..ef327b84af036 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -23,6 +23,8 @@ use rustc_target::abi::{Integer, Size, TargetDataLayout}; use smallvec::SmallVec; use std::{fmt, iter}; +use super::ScalarInt; + #[derive(Copy, Clone, Debug)] pub struct Discr<'tcx> { /// Bit representation of the discriminant (e.g., `-128i8` is `0xFF_u128`). @@ -616,40 +618,38 @@ impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> { impl<'tcx> ty::TyS<'tcx> { /// Returns the maximum value for the given numeric type (including `char`s) /// or returns `None` if the type is not numeric. - pub fn numeric_max_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> { - let val = match self.kind() { + pub fn numeric_max_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option { + match self.kind() { ty::Int(_) | ty::Uint(_) => { let (size, signed) = int_size_and_signed(tcx, self); let val = if signed { signed_max(size) as u128 } else { unsigned_max(size) }; - Some(val) + Some(ScalarInt::from_uint(val, size)) } - ty::Char => Some(std::char::MAX as u128), + ty::Char => Some(ScalarInt::from(std::char::MAX)), ty::Float(fty) => Some(match fty { - ty::FloatTy::F32 => rustc_apfloat::ieee::Single::INFINITY.to_bits(), - ty::FloatTy::F64 => rustc_apfloat::ieee::Double::INFINITY.to_bits(), + ty::FloatTy::F32 => ScalarInt::from(rustc_apfloat::ieee::Single::INFINITY), + ty::FloatTy::F64 => ScalarInt::from(rustc_apfloat::ieee::Double::INFINITY), }), _ => None, - }; - val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self))) + } } /// Returns the minimum value for the given numeric type (including `char`s) /// or returns `None` if the type is not numeric. - pub fn numeric_min_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> { - let val = match self.kind() { + pub fn numeric_min_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option { + match self.kind() { ty::Int(_) | ty::Uint(_) => { let (size, signed) = int_size_and_signed(tcx, self); let val = if signed { size.truncate(signed_min(size) as u128) } else { 0 }; - Some(val) + Some(ScalarInt::from_uint(val, size)) } - ty::Char => Some(0), + ty::Char => Some(ScalarInt::from('\0')), ty::Float(fty) => Some(match fty { - ty::FloatTy::F32 => (-::rustc_apfloat::ieee::Single::INFINITY).to_bits(), - ty::FloatTy::F64 => (-::rustc_apfloat::ieee::Double::INFINITY).to_bits(), + ty::FloatTy::F32 => ScalarInt::from(-::rustc_apfloat::ieee::Single::INFINITY), + ty::FloatTy::F64 => ScalarInt::from(-::rustc_apfloat::ieee::Double::INFINITY), }), _ => None, - }; - val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self))) + } } /// Checks whether values of this type `T` are *moved* or *copied* diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 081ff09f59e91..3af3913596e08 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -21,7 +21,7 @@ use rustc_middle::mir::UserTypeProjection; use rustc_middle::mir::{BorrowKind, Field, Mutability}; use rustc_middle::thir::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange, PatTyProj}; use rustc_middle::ty::subst::{GenericArg, SubstsRef}; -use rustc_middle::ty::{self, AdtDef, DefIdTree, Region, Ty, TyCtxt, UserType}; +use rustc_middle::ty::{self, AdtDef, DefIdTree, Region, ScalarInt, Ty, TyCtxt, UserType}; use rustc_span::{Span, Symbol}; use std::cmp::Ordering; @@ -122,25 +122,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { fn lower_pattern_range( &mut self, ty: Ty<'tcx>, - lo: &'tcx ty::Const<'tcx>, - hi: &'tcx ty::Const<'tcx>, + lo: ScalarInt, + hi: ScalarInt, end: RangeEnd, span: Span, ) -> PatKind<'tcx> { - assert_eq!(lo.ty, ty); - assert_eq!(hi.ty, ty); - let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env, ty); - let lo_const = lo; - let lo = lo - .val - .eval(self.tcx, self.param_env) - .try_to_scalar_int() - .expect("range patterns must be integral"); - let hi = hi - .val - .eval(self.tcx, self.param_env) - .try_to_scalar_int() - .expect("range patterns must be integral"); + let lo_const = ty::Const::from_value(self.tcx, ConstValue::Scalar(lo.into()), ty); + let hi_const = ty::Const::from_value(self.tcx, ConstValue::Scalar(hi.into()), ty); + let cmp = compare_const_vals(self.tcx, lo_const, hi_const, self.param_env, ty); match (end, cmp) { // `x..y` where `x < y`. // Non-empty because the range includes at least `x`. @@ -193,16 +182,18 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { ty: Ty<'tcx>, lo: Option<&PatKind<'tcx>>, hi: Option<&PatKind<'tcx>>, - ) -> Option<(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>)> { + ) -> Option<(ScalarInt, ScalarInt)> { + let eval = + |value: &ty::Const<'tcx>| value.val.eval(self.tcx, self.param_env).try_to_scalar_int(); match (lo, hi) { (Some(PatKind::Constant { value: lo }), Some(PatKind::Constant { value: hi })) => { - Some((lo, hi)) + Some((eval(lo)?, eval(hi)?)) } (Some(PatKind::Constant { value: lo }), None) => { - Some((lo, ty.numeric_max_val(self.tcx)?)) + Some((eval(lo)?, ty.numeric_max_val(self.tcx)?)) } (None, Some(PatKind::Constant { value: hi })) => { - Some((ty.numeric_min_val(self.tcx)?, hi)) + Some((ty.numeric_min_val(self.tcx)?, eval(hi)?)) } _ => None, } diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs index 021136ac5e019..1ffb665feb675 100644 --- a/src/tools/clippy/clippy_lints/src/enum_clike.rs +++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs @@ -1,7 +1,6 @@ //! lint on C-like enums that are `repr(isize/usize)` and have values that //! don't fit into an `i32` -use clippy_utils::consts::{miri_to_const, Constant}; use clippy_utils::diagnostics::span_lint; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -50,8 +49,9 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant { .tcx .const_eval_poly(def_id.to_def_id()) .ok() - .map(|val| rustc_middle::ty::Const::from_value(cx.tcx, val, ty)); - if let Some(Constant::Int(val)) = constant.and_then(miri_to_const) { + .and_then(|c| c.try_to_scalar_int()); + if let Some(scalar) = constant { + let val = scalar.to_bits(cx.tcx.layout_of(cx.param_env.and(ty)).unwrap().size).unwrap(); if let ty::Adt(adt, _) = ty.kind() { if adt.is_enum() { ty = adt.repr.discr_type().to_ty(cx.tcx); diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs index f1e3492c4ecc5..d75c8b0a5fc2a 100644 --- a/src/tools/clippy/clippy_lints/src/matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches.rs @@ -25,6 +25,7 @@ use rustc_hir::{HirIdMap, HirIdSet}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty, TyS, VariantDef}; +use rustc_middle::mir::{self, interpret::ConstValue}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{Span, Spanned}; @@ -1533,11 +1534,17 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind { let lhs = match lhs { Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0, - None => miri_to_const(ty.numeric_min_val(cx.tcx)?)?, + None => miri_to_const(mir::ConstantKind::Val( + ConstValue::Scalar(ty.numeric_min_val(cx.tcx)?.into()), + ty, + ))?, }; let rhs = match rhs { Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0, - None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?, + None => miri_to_const(mir::ConstantKind::Val( + ConstValue::Scalar(ty.numeric_max_val(cx.tcx)?.into()), + ty, + ))?, }; let rhs = match range_end { RangeEnd::Included => Bound::Included(rhs), diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 15c27d1a996d7..b62a0e08cf769 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -7,7 +7,7 @@ use rustc_data_structures::sync::Lrc; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, QPath, UnOp}; use rustc_lint::LateContext; -use rustc_middle::mir::interpret::Scalar; +use rustc_middle::mir; use rustc_middle::ty::subst::{Subst, SubstsRef}; use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; @@ -354,7 +354,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { None, ) .ok() - .map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?; + .map(|val| mir::ConstantKind::Val(val, ty))?; let result = miri_to_const(result); if result.is_some() { self.needed_resolution = true; @@ -505,34 +505,28 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { } } -pub fn miri_to_const(result: &ty::Const<'_>) -> Option { +pub fn miri_to_const(result: mir::ConstantKind<'tcx>) -> Option { use rustc_middle::mir::interpret::ConstValue; - match result.val { - ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int(int))) => { - match result.ty.kind() { - ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)), - ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))), + match *result.ty().kind() { + ty::Bool => Some(Constant::Bool(result.try_to_scalar_int()? == ScalarInt::TRUE)), + ty::Uint(_) | ty::Int(_) => { + let int = result.try_to_scalar_int()?; + Some(Constant::Int(int.assert_bits(int.size()))) + } ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits( - int.try_into().expect("invalid f32 bit representation"), + result.try_to_scalar_int()?.try_into().expect("invalid f32 bit representation"), ))), ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits( - int.try_into().expect("invalid f64 bit representation"), + result.try_to_scalar_int()?.try_into().expect("invalid f64 bit representation"), ))), - ty::RawPtr(type_and_mut) => { - if let ty::Uint(_) = type_and_mut.ty.kind() { - return Some(Constant::RawPtr(int.assert_bits(int.size()))); + ty::RawPtr(_) => { + let int = result.try_to_scalar_int()?; + Some(Constant::RawPtr(int.assert_bits(int.size()))) } - None - }, - // FIXME: implement other conversions. - _ => None, - } - }, - ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty.kind() { ty::Ref(_, tam, _) => match tam.kind() { - ty::Str => String::from_utf8( - data.inspect_with_uninit_and_ptr_outside_interpreter(start..end) - .to_owned(), + ty::Str => match result.try_to_value()? { + ConstValue::Slice { data, start, end } => String::from_utf8( + data.inspect_with_uninit_and_ptr_outside_interpreter(start..end).to_owned(), ) .ok() .map(Constant::Str), @@ -540,9 +534,9 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option { }, _ => None, }, - ty::ConstKind::Value(ConstValue::ByRef { alloc, offset: _ }) => match result.ty.kind() { - ty::Array(sub_type, len) => match sub_type.kind() { - ty::Float(FloatTy::F32) => match miri_to_const(len) { + ty::Array(sub_type, len) => match result.try_to_value()? { + ConstValue::ByRef { alloc, offset: _ } => match sub_type.kind() { + ty::Float(FloatTy::F32) => match miri_to_const(len.into()) { Some(Constant::Int(len)) => alloc .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * len as usize)) .to_owned() @@ -556,7 +550,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option { .map(Constant::Vec), _ => None, }, - ty::Float(FloatTy::F64) => match miri_to_const(len) { + ty::Float(FloatTy::F64) => match miri_to_const(len.into()) { Some(Constant::Int(len)) => alloc .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * len as usize)) .to_owned() From 562cbc9c5b3121b1f29d06dc059ee66652bc476f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 1 Apr 2021 14:03:40 +0000 Subject: [PATCH 6/6] Stop using ty::Const in `deref_const` and `destructure_const` in preparation of value trees making such operations on `ty::Const` obsolete. --- .../rustc_codegen_ssa/src/mir/constant.rs | 10 +++--- compiler/rustc_middle/src/mir/mod.rs | 21 ++++++++++++ compiler/rustc_middle/src/mir/query.rs | 4 +-- .../rustc_middle/src/mir/type_foldable.rs | 10 ++++++ compiler/rustc_middle/src/query/mod.rs | 6 ++-- compiler/rustc_middle/src/ty/print/pretty.rs | 6 ++-- compiler/rustc_middle/src/ty/relate.rs | 23 ++++++++----- compiler/rustc_mir/src/const_eval/mod.rs | 20 ++++++----- compiler/rustc_mir/src/lib.rs | 8 ++--- .../src/thir/pattern/const_to_pat.rs | 33 ++++++++++++------- compiler/rustc_query_impl/src/keys.rs | 9 +++++ .../clippy/clippy_lints/src/non_copy_const.rs | 14 ++++---- 12 files changed, 109 insertions(+), 55 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index fa8a53e60b169..f3e4b32300b4f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -57,15 +57,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) -> (Bx::Value, Ty<'tcx>) { constant .map(|val| { - let field_ty = ty.builtin_index().unwrap(); - let c = ty::Const::from_value(bx.tcx(), val, ty); let values: Vec<_> = bx .tcx() - .destructure_const(ty::ParamEnv::reveal_all().and(&c)) + .destructure_const(ty::ParamEnv::reveal_all().and((val, ty))) .fields .iter() - .map(|field| { - if let Some(prim) = field.val.try_to_scalar() { + .map(|(field, field_ty)| { + if let Some(prim) = field.try_to_scalar() { let layout = bx.layout_of(field_ty); let scalar = match layout.abi { Abi::Scalar(ref x) => x, @@ -78,7 +76,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }) .collect(); let llval = bx.const_struct(&values, false); - (llval, c.ty) + (llval, ty) }) .unwrap_or_else(|_| { bx.tcx().sess.span_err(span, "could not evaluate shuffle_indices at compile time"); diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 672686410f9bf..3181ff66ab7f8 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2543,6 +2543,27 @@ impl ConstantKind<'tcx> { } } + #[inline] + /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type. + pub fn eval_bits( + &self, + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + ) -> u128 { + match self { + Self::Ty(ct) => ct.eval_bits(tcx, param_env, ty), + Self::Val(val, t) => { + assert_eq!(*t, ty); + let size = tcx + .layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)) + .expect("could not normalize type") + .size; + val.try_to_scalar_int().unwrap().assert_bits(size) + } + } + } + #[inline] pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option { match self { diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 4fb737f463a86..685ac89ee0bd8 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -16,7 +16,7 @@ use smallvec::SmallVec; use std::cell::Cell; use std::fmt::{self, Debug}; -use super::{Field, SourceInfo}; +use super::{interpret::ConstValue, Field, SourceInfo}; #[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] pub enum UnsafetyViolationKind { @@ -379,7 +379,7 @@ pub enum ClosureOutlivesSubject<'tcx> { #[derive(Copy, Clone, Debug, HashStable)] pub struct DestructuredConst<'tcx> { pub variant: Option, - pub fields: &'tcx [&'tcx ty::Const<'tcx>], + pub fields: &'tcx [(ConstValue<'tcx>, Ty<'tcx>)], } /// Coverage information summarized from a MIR if instrumented for source code coverage (see diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index f3124e5bf424e..c7bcae947ef98 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -367,3 +367,13 @@ impl<'tcx> TypeFoldable<'tcx> for ConstantKind<'tcx> { } } } + +impl<'tcx> TypeFoldable<'tcx> for interpret::ConstValue<'tcx> { + fn super_fold_with>(self, _folder: &mut F) -> Self { + self + } + + fn super_visit_with>(&self, _visitor: &mut V) -> ControlFlow { + ControlFlow::CONTINUE + } +} diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 9a2f1149316e2..471bb68a7db52 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -828,7 +828,7 @@ rustc_queries! { /// Destructure a constant ADT or array into its variant index and its /// field values. query destructure_const( - key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>> + key: ty::ParamEnvAnd<'tcx, (ConstValue<'tcx>, Ty<'tcx>)> ) -> mir::DestructuredConst<'tcx> { desc { "destructure constant" } } @@ -836,8 +836,8 @@ rustc_queries! { /// Dereference a constant reference or raw pointer and turn the result into a constant /// again. query deref_const( - key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>> - ) -> &'tcx ty::Const<'tcx> { + key: ty::ParamEnvAnd<'tcx, (ConstValue<'tcx>, Ty<'tcx>)> + ) -> (ConstValue<'tcx>, Ty<'tcx>) { desc { "deref constant" } } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 44fa4eb71d801..1ca7fef102873 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1200,10 +1200,8 @@ pub trait PrettyPrinter<'tcx>: // FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the // correct `ty::ParamEnv` to allow printing *all* constant values. (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_param_types_or_consts() => { - let contents = self.tcx().destructure_const( - ty::ParamEnv::reveal_all() - .and(self.tcx().mk_const(ty::Const { val: ty::ConstKind::Value(ct), ty })), - ); + let contents = + self.tcx().destructure_const(ty::ParamEnv::reveal_all().and((ct, ty))); let fields = contents.fields.iter().copied(); match *ty.kind() { diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 3f426b13688fe..d1ab23b6fd3e8 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -546,7 +546,7 @@ pub fn super_relate_consts>( (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) => a_p.index == b_p.index, (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2, (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => { - check_const_value_eq(relation, a_val, b_val, a, b)? + check_const_value_eq(relation, a_val, b_val, a.ty, b.ty)? } (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) @@ -585,10 +585,8 @@ fn check_const_value_eq>( relation: &mut R, a_val: ConstValue<'tcx>, b_val: ConstValue<'tcx>, - // FIXME(oli-obk): these arguments should go away with valtrees - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, - // FIXME(oli-obk): this should just be `bool` with valtrees + a_ty: Ty<'tcx>, + b_ty: Ty<'tcx>, ) -> RelateResult<'tcx, bool> { let tcx = relation.tcx(); Ok(match (a_val, b_val) { @@ -610,13 +608,20 @@ fn check_const_value_eq>( } (ConstValue::ByRef { .. }, ConstValue::ByRef { .. }) => { - let a_destructured = tcx.destructure_const(relation.param_env().and(a)); - let b_destructured = tcx.destructure_const(relation.param_env().and(b)); + let a_destructured = tcx.destructure_const(relation.param_env().and((a_val, a_ty))); + let b_destructured = tcx.destructure_const(relation.param_env().and((b_val, b_ty))); // Both the variant and each field have to be equal. if a_destructured.variant == b_destructured.variant { - for (a_field, b_field) in iter::zip(a_destructured.fields, b_destructured.fields) { - relation.consts(a_field, b_field)?; + for (&(a_val, a_ty), &(b_val, b_ty)) in + iter::zip(a_destructured.fields, b_destructured.fields) + { + let is_match = check_const_value_eq(relation, a_val, b_val, a_ty, b_ty)?; + if !is_match { + let a = ty::Const::from_value(relation.tcx(), a_val, a_ty); + let b = ty::Const::from_value(relation.tcx(), b_val, b_ty); + return Err(TypeError::ConstMismatch(expected_found(relation, a, b))); + } } true diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs index 6a514e9f62fce..6609205616dee 100644 --- a/compiler/rustc_mir/src/const_eval/mod.rs +++ b/compiler/rustc_mir/src/const_eval/mod.rs @@ -3,7 +3,7 @@ use std::convert::TryFrom; use rustc_hir::Mutability; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{ mir::{self, interpret::ConstAlloc}, ty::ScalarInt, @@ -139,14 +139,15 @@ fn const_to_valtree_inner<'tcx>( pub(crate) fn destructure_const<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - val: &'tcx ty::Const<'tcx>, + val: ConstValue<'tcx>, + ty: Ty<'tcx>, ) -> mir::DestructuredConst<'tcx> { trace!("destructure_const: {:?}", val); let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); - let op = ecx.const_to_op(val, None).unwrap(); + let op = ecx.const_val_to_op(val, ty, None).unwrap(); // We go to `usize` as we cannot allocate anything bigger anyway. - let (field_count, variant, down) = match val.ty.kind() { + let (field_count, variant, down) = match op.layout.ty.kind() { ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op), ty::Adt(def, _) if def.variants.is_empty() => { return mir::DestructuredConst { variant: None, fields: &[] }; @@ -163,7 +164,7 @@ pub(crate) fn destructure_const<'tcx>( let fields_iter = (0..field_count).map(|i| { let field_op = ecx.operand_field(&down, i).unwrap(); let val = op_to_const(&ecx, &field_op); - ty::Const::from_value(tcx, val, field_op.layout.ty) + (val, field_op.layout.ty) }); let fields = tcx.arena.alloc_from_iter(fields_iter); @@ -173,11 +174,12 @@ pub(crate) fn destructure_const<'tcx>( pub(crate) fn deref_const<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - val: &'tcx ty::Const<'tcx>, -) -> &'tcx ty::Const<'tcx> { + val: ConstValue<'tcx>, + ty: Ty<'tcx>, +) -> (ConstValue<'tcx>, Ty<'tcx>) { trace!("deref_const: {:?}", val); let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false); - let op = ecx.const_to_op(val, None).unwrap(); + let op = ecx.const_val_to_op(val, ty, None).unwrap(); let mplace = ecx.deref_operand(&op).unwrap(); if let Scalar::Ptr(ptr) = mplace.ptr { assert_eq!( @@ -203,5 +205,5 @@ pub(crate) fn deref_const<'tcx>( }, }; - tcx.mk_const(ty::Const { val: ty::ConstKind::Value(op_to_const(&ecx, &mplace.into())), ty }) + (op_to_const(&ecx, &mplace.into()), ty) } diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index a58ded9cfd3a4..3303ec4ebf71c 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -61,15 +61,15 @@ pub fn provide(providers: &mut Providers) { providers.mir_callgraph_reachable = transform::inline::cycle::mir_callgraph_reachable; providers.mir_inliner_callees = transform::inline::cycle::mir_inliner_callees; providers.destructure_const = |tcx, param_env_and_value| { - let (param_env, value) = param_env_and_value.into_parts(); - const_eval::destructure_const(tcx, param_env, value) + let (param_env, (value, ty)) = param_env_and_value.into_parts(); + const_eval::destructure_const(tcx, param_env, value, ty) }; providers.const_to_valtree = |tcx, param_env_and_value| { let (param_env, raw) = param_env_and_value.into_parts(); const_eval::const_to_valtree(tcx, param_env, raw) }; providers.deref_const = |tcx, param_env_and_value| { - let (param_env, value) = param_env_and_value.into_parts(); - const_eval::deref_const(tcx, param_env, value) + let (param_env, (value, ty)) = param_env_and_value.into_parts(); + const_eval::deref_const(tcx, param_env, value, ty) }; } 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 369fff00456a7..dffadc7aab1d6 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 @@ -1,6 +1,7 @@ use rustc_hir as hir; use rustc_index::vec::Idx; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_middle::mir::interpret::ConstValue; use rustc_middle::mir::Field; use rustc_middle::thir::{FieldPat, Pat, PatKind}; use rustc_middle::ty::print::with_no_trimmed_paths; @@ -249,11 +250,13 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { fn field_pats( &self, - vals: impl Iterator>, + vals: impl Iterator, Ty<'tcx>)>, ) -> Result>, FallbackToConstRef> { + let tcx = self.tcx(); vals.enumerate() - .map(|(idx, val)| { + .map(|(idx, (val, ty))| { let field = Field::new(idx); + let val = ty::Const::from_value(tcx, val, ty); Ok(FieldPat { field, pattern: self.recur(val, false)? }) }) .collect() @@ -357,7 +360,9 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { PatKind::Wild } ty::Adt(adt_def, substs) if adt_def.is_enum() => { - let destructured = tcx.destructure_const(param_env.and(cv)); + let destructured = tcx.destructure_const( + param_env.and((cv.val.eval(tcx, param_env).try_to_value().unwrap(), cv.ty)), + ); PatKind::Variant { adt_def, substs, @@ -368,15 +373,19 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { } } ty::Tuple(_) | ty::Adt(_, _) => { - let destructured = tcx.destructure_const(param_env.and(cv)); + let destructured = tcx.destructure_const( + param_env.and((cv.val.eval(tcx, param_env).try_to_value().unwrap(), cv.ty)), + ); PatKind::Leaf { subpatterns: self.field_pats(destructured.fields.iter().copied())? } } ty::Array(..) => PatKind::Array { prefix: tcx - .destructure_const(param_env.and(cv)) + .destructure_const( + param_env.and((cv.val.eval(tcx, param_env).try_to_value().unwrap(), cv.ty)), + ) .fields .iter() - .map(|val| self.recur(val, false)) + .map(|&(val, ty)| self.recur(ty::Const::from_value(tcx, val, ty), false)) .collect::>()?, slice: None, suffix: Vec::new(), @@ -404,7 +413,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // arrays. ty::Array(..) if !self.treat_byte_string_as_slice => { let old = self.behind_reference.replace(true); - let array = tcx.deref_const(self.param_env.and(cv)); + let array = tcx.deref_const(self.param_env.and((cv.val.eval(tcx, param_env).try_to_value().unwrap(), cv.ty))); let val = PatKind::Deref { subpattern: Pat { kind: Box::new(PatKind::Array { @@ -412,7 +421,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { .destructure_const(param_env.and(array)) .fields .iter() - .map(|val| self.recur(val, false)) + .map(|&(val, ty)| self.recur(ty::Const::from_value(tcx, val, ty), false)) .collect::>()?, slice: None, suffix: vec![], @@ -430,7 +439,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // pattern. ty::Slice(elem_ty) => { let old = self.behind_reference.replace(true); - let array = tcx.deref_const(self.param_env.and(cv)); + let array = tcx.deref_const(self.param_env.and((cv.val.eval(tcx, param_env).try_to_value().unwrap(), cv.ty))); let val = PatKind::Deref { subpattern: Pat { kind: Box::new(PatKind::Slice { @@ -438,7 +447,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { .destructure_const(param_env.and(array)) .fields .iter() - .map(|val| self.recur(val, false)) + .map(|&(val, ty)| self.recur(ty::Const::from_value(tcx, val, ty), false)) .collect::>()?, slice: None, suffix: vec![], @@ -493,7 +502,9 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // we fall back to a const pattern. If we do not do this, we may end up with // a !structural-match constant that is not of reference type, which makes it // very hard to invoke `PartialEq::eq` on it as a fallback. - let val = match self.recur(tcx.deref_const(self.param_env.and(cv)), false) { + let (val, ty) = tcx.deref_const(self.param_env.and((cv.val.eval(tcx, param_env).try_to_value().unwrap(), cv.ty))); + let deref_cv = ty::Const::from_value(tcx, val, ty); + let val = match self.recur(deref_cv, false) { Ok(subpattern) => PatKind::Deref { subpattern }, Err(_) => PatKind::Constant { value: cv }, }; diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs index b3cc7de4662a5..5c711673e6240 100644 --- a/compiler/rustc_query_impl/src/keys.rs +++ b/compiler/rustc_query_impl/src/keys.rs @@ -311,6 +311,15 @@ impl<'tcx> Key for &'tcx ty::Const<'tcx> { } } +impl<'tcx> Key for (mir::interpret::ConstValue<'tcx>, Ty<'tcx>) { + fn query_crate_is_local(&self) -> bool { + true + } + fn default_span(&self, _: TyCtxt<'_>) -> Span { + DUMMY_SP + } +} + impl<'tcx> Key for Ty<'tcx> { #[inline(always)] fn query_crate_is_local(&self) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index d775cd7c7f740..15f4c04857651 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -16,7 +16,7 @@ use rustc_infer::traits::specialization_graph; use rustc_lint::{LateContext, LateLintPass, Lint}; use rustc_middle::mir::interpret::{ConstValue, ErrorHandled}; use rustc_middle::ty::adjustment::Adjust; -use rustc_middle::ty::{self, AssocKind, Const, Ty}; +use rustc_middle::ty::{self, AssocKind, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{InnerSpan, Span, DUMMY_SP}; use rustc_typeck::hir_ty_to_ty; @@ -129,15 +129,15 @@ fn is_value_unfrozen_raw<'tcx>( result: Result, ErrorHandled>, ty: Ty<'tcx>, ) -> bool { - fn inner<'tcx>(cx: &LateContext<'tcx>, val: &'tcx Const<'tcx>) -> bool { - match val.ty.kind() { + fn inner<'tcx>(cx: &LateContext<'tcx>, val: ConstValue<'tcx>, ty: Ty<'tcx>) -> bool { + match ty.kind() { // the fact that we have to dig into every structs to search enums // leads us to the point checking `UnsafeCell` directly is the only option. ty::Adt(ty_def, ..) if Some(ty_def.did) == cx.tcx.lang_items().unsafe_cell_type() => true, ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => { - let val = cx.tcx.destructure_const(cx.param_env.and(val)); - val.fields.iter().any(|field| inner(cx, field)) - }, + let val = cx.tcx.destructure_const(cx.param_env.and((val, ty))); + val.fields.iter().any(|&(f, f_ty)| inner(cx, f, f_ty)) + } _ => false, } } @@ -167,7 +167,7 @@ fn is_value_unfrozen_raw<'tcx>( // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none). err == ErrorHandled::TooGeneric }, - |val| inner(cx, Const::from_value(cx.tcx, val, ty)), + |val| inner(cx, val, ty), ) }