summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_middle/src/mir/consts.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
commitef24de24a82fe681581cc130f342363c47c0969a (patch)
tree0d494f7e1a38b95c92426f58fe6eaa877303a86c /compiler/rustc_middle/src/mir/consts.rs
parentReleasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-ef24de24a82fe681581cc130f342363c47c0969a.tar.xz
rustc-ef24de24a82fe681581cc130f342363c47c0969a.zip
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_middle/src/mir/consts.rs')
-rw-r--r--compiler/rustc_middle/src/mir/consts.rs89
1 files changed, 84 insertions, 5 deletions
diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs
index 7c8a57b84..a9d09709e 100644
--- a/compiler/rustc_middle/src/mir/consts.rs
+++ b/compiler/rustc_middle/src/mir/consts.rs
@@ -3,6 +3,7 @@ use std::fmt::{self, Debug, Display, Formatter};
use rustc_hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{self as hir};
+use rustc_session::RemapFileNameExt;
use rustc_span::Span;
use rustc_target::abi::{HasDataLayout, Size};
@@ -172,6 +173,24 @@ impl<'tcx> ConstValue<'tcx> {
let end = end.try_into().unwrap();
Some(data.inner().inspect_with_uninit_and_ptr_outside_interpreter(start..end))
}
+
+ /// Check if a constant may contain provenance information. This is used by MIR opts.
+ /// Can return `true` even if there is no provenance.
+ pub fn may_have_provenance(&self, tcx: TyCtxt<'tcx>, size: Size) -> bool {
+ match *self {
+ ConstValue::ZeroSized | ConstValue::Scalar(Scalar::Int(_)) => return false,
+ ConstValue::Scalar(Scalar::Ptr(..)) => return true,
+ // It's hard to find out the part of the allocation we point to;
+ // just conservatively check everything.
+ ConstValue::Slice { data, meta: _ } => !data.inner().provenance().ptrs().is_empty(),
+ ConstValue::Indirect { alloc_id, offset } => !tcx
+ .global_alloc(alloc_id)
+ .unwrap_memory()
+ .inner()
+ .provenance()
+ .range_empty(super::AllocRange::from(offset..offset + size), &tcx),
+ }
+ }
}
///////////////////////////////////////////////////////////////////////////
@@ -213,10 +232,10 @@ impl<'tcx> Const<'tcx> {
pub fn try_to_scalar(self) -> Option<Scalar> {
match self {
Const::Ty(c) => match c.kind() {
- ty::ConstKind::Value(valtree) => match valtree {
- ty::ValTree::Leaf(scalar_int) => Some(Scalar::Int(scalar_int)),
- ty::ValTree::Branch(_) => None,
- },
+ ty::ConstKind::Value(valtree) if c.ty().is_primitive() => {
+ // A valtree of a type where leaves directly represent the scalar const value.
+ Some(valtree.unwrap_leaf().into())
+ }
_ => None,
},
Const::Val(val, _) => val.try_to_scalar(),
@@ -279,7 +298,16 @@ impl<'tcx> Const<'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Option<Scalar> {
- self.eval(tcx, param_env, None).ok()?.try_to_scalar()
+ match self {
+ Const::Ty(c) if c.ty().is_primitive() => {
+ // Avoid the `valtree_to_const_val` query. Can only be done on primitive types that
+ // are valtree leaves, and *not* on references. (References should return the
+ // pointer here, which valtrees don't represent.)
+ let val = c.eval(tcx, param_env, None).ok()?;
+ Some(val.unwrap_leaf().into())
+ }
+ _ => self.eval(tcx, param_env, None).ok()?.try_to_scalar(),
+ }
}
#[inline]
@@ -476,6 +504,40 @@ impl<'tcx> Const<'tcx> {
_ => Self::Ty(c),
}
}
+
+ /// Return true if any evaluation of this constant always returns the same value,
+ /// taking into account even pointer identity tests.
+ pub fn is_deterministic(&self) -> bool {
+ // Some constants may generate fresh allocations for pointers they contain,
+ // so using the same constant twice can yield two different results:
+ // - valtrees purposefully generate new allocations
+ // - ConstValue::Slice also generate new allocations
+ match self {
+ Const::Ty(c) => match c.kind() {
+ ty::ConstKind::Param(..) => true,
+ // A valtree may be a reference. Valtree references correspond to a
+ // different allocation each time they are evaluated. Valtrees for primitive
+ // types are fine though.
+ ty::ConstKind::Value(_) => c.ty().is_primitive(),
+ ty::ConstKind::Unevaluated(..) | ty::ConstKind::Expr(..) => false,
+ // This can happen if evaluation of a constant failed. The result does not matter
+ // much since compilation is doomed.
+ ty::ConstKind::Error(..) => false,
+ // Should not appear in runtime MIR.
+ ty::ConstKind::Infer(..)
+ | ty::ConstKind::Bound(..)
+ | ty::ConstKind::Placeholder(..) => bug!(),
+ },
+ Const::Unevaluated(..) => false,
+ // If the same slice appears twice in the MIR, we cannot guarantee that we will
+ // give the same `AllocId` to the data.
+ Const::Val(ConstValue::Slice { .. }, _) => false,
+ Const::Val(
+ ConstValue::ZeroSized | ConstValue::Scalar(_) | ConstValue::Indirect { .. },
+ _,
+ ) => true,
+ }
+ }
}
/// An unevaluated (potentially generic) constant used in MIR.
@@ -520,3 +582,20 @@ impl<'tcx> Display for Const<'tcx> {
}
}
}
+
+///////////////////////////////////////////////////////////////////////////
+/// Const-related utilities
+
+impl<'tcx> TyCtxt<'tcx> {
+ pub fn span_as_caller_location(self, span: Span) -> ConstValue<'tcx> {
+ let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
+ let caller = self.sess.source_map().lookup_char_pos(topmost.lo());
+ self.const_caller_location(
+ rustc_span::symbol::Symbol::intern(
+ &caller.file.name.for_codegen(&self.sess).to_string_lossy(),
+ ),
+ caller.line as u32,
+ caller.col_display as u32 + 1,
+ )
+ }
+}