mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 07:14:28 +00:00
Auto merge of #3074 - rust-lang:rustup-2023-09-22, r=RalfJung
Automatic sync from rustc
This commit is contained in:
commit
ce33ca0a1e
@ -1308,7 +1308,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
|
||||
fn lower_asyncness(&mut self, a: Async) -> hir::IsAsync {
|
||||
match a {
|
||||
Async::Yes { .. } => hir::IsAsync::Async,
|
||||
Async::Yes { span, .. } => hir::IsAsync::Async(span),
|
||||
Async::No => hir::IsAsync::NotAsync,
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ use rustc_index::IndexSlice;
|
||||
use rustc_infer::infer::LateBoundRegionConversionTime;
|
||||
use rustc_middle::mir::tcx::PlaceTy;
|
||||
use rustc_middle::mir::{
|
||||
AggregateKind, CallSource, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location,
|
||||
AggregateKind, CallSource, ConstOperand, FakeReadCause, Local, LocalInfo, LocalKind, Location,
|
||||
Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
|
||||
TerminatorKind,
|
||||
};
|
||||
@ -101,12 +101,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||
let terminator = self.body[location.block].terminator();
|
||||
debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator);
|
||||
if let TerminatorKind::Call {
|
||||
func: Operand::Constant(box Constant { literal, .. }),
|
||||
func: Operand::Constant(box ConstOperand { const_, .. }),
|
||||
args,
|
||||
..
|
||||
} = &terminator.kind
|
||||
{
|
||||
if let ty::FnDef(id, _) = *literal.ty().kind() {
|
||||
if let ty::FnDef(id, _) = *const_.ty().kind() {
|
||||
debug!("add_moved_or_invoked_closure_note: id={:?}", id);
|
||||
if Some(self.infcx.tcx.parent(id)) == self.infcx.tcx.lang_items().fn_once_trait() {
|
||||
let closure = match args.first() {
|
||||
|
@ -302,7 +302,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
|
||||
if free_region.bound_region.is_named() {
|
||||
// A named region that is actually named.
|
||||
Some(RegionName { name, source: RegionNameSource::NamedFreeRegion(span) })
|
||||
} else if let hir::IsAsync::Async = tcx.asyncness(self.mir_hir_id().owner) {
|
||||
} else if tcx.asyncness(self.mir_hir_id().owner).is_async() {
|
||||
// If we spuriously thought that the region is named, we should let the
|
||||
// system generate a true name for error messages. Currently this can
|
||||
// happen if we have an elided name in an async fn for example: the
|
||||
|
@ -4,8 +4,7 @@ use crate::BorrowckInferCtxt;
|
||||
use rustc_index::IndexSlice;
|
||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||
use rustc_middle::mir::visit::{MutVisitor, TyContext};
|
||||
use rustc_middle::mir::Constant;
|
||||
use rustc_middle::mir::{Body, Location, Promoted};
|
||||
use rustc_middle::mir::{Body, ConstOperand, Location, Promoted};
|
||||
use rustc_middle::ty::GenericArgsRef;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_span::{Span, Symbol};
|
||||
@ -117,9 +116,9 @@ impl<'a, 'tcx> MutVisitor<'tcx> for RegionRenumberer<'a, 'tcx> {
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn visit_constant(&mut self, constant: &mut Constant<'tcx>, location: Location) {
|
||||
let literal = constant.literal;
|
||||
constant.literal = self.renumber_regions(literal, || RegionCtxt::Location(location));
|
||||
fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) {
|
||||
let const_ = constant.const_;
|
||||
constant.const_ = self.renumber_regions(const_, || RegionCtxt::Location(location));
|
||||
debug!("constant: {:#?}", constant);
|
||||
}
|
||||
}
|
||||
|
@ -302,11 +302,11 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
||||
self.sanitize_place(place, location, context);
|
||||
}
|
||||
|
||||
fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
|
||||
fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, location: Location) {
|
||||
debug!(?constant, ?location, "visit_constant");
|
||||
|
||||
self.super_constant(constant, location);
|
||||
let ty = self.sanitize_type(constant, constant.literal.ty());
|
||||
let ty = self.sanitize_type(constant, constant.const_.ty());
|
||||
|
||||
self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| {
|
||||
let live_region_vid =
|
||||
@ -328,7 +328,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
||||
|
||||
if let Some(annotation_index) = constant.user_ty {
|
||||
if let Err(terr) = self.cx.relate_type_and_user_type(
|
||||
constant.literal.ty(),
|
||||
constant.const_.ty(),
|
||||
ty::Variance::Invariant,
|
||||
&UserTypeProjection { base: annotation_index, projs: vec![] },
|
||||
locations,
|
||||
@ -340,20 +340,20 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
||||
constant,
|
||||
"bad constant user type {:?} vs {:?}: {:?}",
|
||||
annotation,
|
||||
constant.literal.ty(),
|
||||
constant.const_.ty(),
|
||||
terr,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
let tcx = self.tcx();
|
||||
let maybe_uneval = match constant.literal {
|
||||
ConstantKind::Ty(ct) => match ct.kind() {
|
||||
let maybe_uneval = match constant.const_ {
|
||||
Const::Ty(ct) => match ct.kind() {
|
||||
ty::ConstKind::Unevaluated(_) => {
|
||||
bug!("should not encounter unevaluated ConstantKind::Ty here, got {:?}", ct)
|
||||
bug!("should not encounter unevaluated Const::Ty here, got {:?}", ct)
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
ConstantKind::Unevaluated(uv, _) => Some(uv),
|
||||
Const::Unevaluated(uv, _) => Some(uv),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
@ -384,7 +384,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
||||
check_err(self, promoted_body, ty, promoted_ty);
|
||||
} else {
|
||||
self.cx.ascribe_user_type(
|
||||
constant.literal.ty(),
|
||||
constant.const_.ty(),
|
||||
UserType::TypeOf(uv.def, UserArgs { args: uv.args, user_self_ty: None }),
|
||||
locations.span(&self.cx.body),
|
||||
);
|
||||
@ -392,7 +392,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
||||
} else if let Some(static_def_id) = constant.check_static_ptr(tcx) {
|
||||
let unnormalized_ty = tcx.type_of(static_def_id).instantiate_identity();
|
||||
let normalized_ty = self.cx.normalize(unnormalized_ty, locations);
|
||||
let literal_ty = constant.literal.ty().builtin_deref(true).unwrap().ty;
|
||||
let literal_ty = constant.const_.ty().builtin_deref(true).unwrap().ty;
|
||||
|
||||
if let Err(terr) = self.cx.eq_types(
|
||||
literal_ty,
|
||||
@ -404,7 +404,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
if let ty::FnDef(def_id, args) = *constant.literal.ty().kind() {
|
||||
if let ty::FnDef(def_id, args) = *constant.const_.ty().kind() {
|
||||
let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, args);
|
||||
self.cx.normalize_and_prove_instantiated_predicates(
|
||||
def_id,
|
||||
@ -1801,9 +1801,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
debug!(?op, ?location, "check_operand");
|
||||
|
||||
if let Operand::Constant(constant) = op {
|
||||
let maybe_uneval = match constant.literal {
|
||||
ConstantKind::Val(..) | ConstantKind::Ty(_) => None,
|
||||
ConstantKind::Unevaluated(uv, _) => Some(uv),
|
||||
let maybe_uneval = match constant.const_ {
|
||||
Const::Val(..) | Const::Ty(_) => None,
|
||||
Const::Unevaluated(uv, _) => Some(uv),
|
||||
};
|
||||
|
||||
if let Some(uv) = maybe_uneval {
|
||||
|
@ -580,7 +580,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
|
||||
BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(..) => {
|
||||
let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id);
|
||||
if self.mir_def.to_def_id() == typeck_root_def_id {
|
||||
let args =
|
||||
|
@ -64,9 +64,9 @@ pub(crate) fn codegen_tls_ref<'tcx>(
|
||||
|
||||
pub(crate) fn eval_mir_constant<'tcx>(
|
||||
fx: &FunctionCx<'_, '_, 'tcx>,
|
||||
constant: &Constant<'tcx>,
|
||||
constant: &ConstOperand<'tcx>,
|
||||
) -> (ConstValue<'tcx>, Ty<'tcx>) {
|
||||
let cv = fx.monomorphize(constant.literal);
|
||||
let cv = fx.monomorphize(constant.const_);
|
||||
// This cannot fail because we checked all required_consts in advance.
|
||||
let val = cv
|
||||
.eval(fx.tcx, ty::ParamEnv::reveal_all(), Some(constant.span))
|
||||
@ -76,7 +76,7 @@ pub(crate) fn eval_mir_constant<'tcx>(
|
||||
|
||||
pub(crate) fn codegen_constant_operand<'tcx>(
|
||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||
constant: &Constant<'tcx>,
|
||||
constant: &ConstOperand<'tcx>,
|
||||
) -> CValue<'tcx> {
|
||||
let (const_val, ty) = eval_mir_constant(fx, constant);
|
||||
codegen_const_value(fx, const_val, ty)
|
||||
|
@ -252,8 +252,8 @@ pub(crate) fn codegen_inline_asm<'tcx>(
|
||||
CInlineAsmOperand::Const { value }
|
||||
}
|
||||
InlineAsmOperand::SymFn { ref value } => {
|
||||
let literal = fx.monomorphize(value.literal);
|
||||
if let ty::FnDef(def_id, args) = *literal.ty().kind() {
|
||||
let const_ = fx.monomorphize(value.const_);
|
||||
if let ty::FnDef(def_id, args) = *const_.ty().kind() {
|
||||
let instance = ty::Instance::resolve_for_fn_ptr(
|
||||
fx.tcx,
|
||||
ty::ParamEnv::reveal_all(),
|
||||
|
@ -1,4 +1,4 @@
|
||||
use rustc_middle::mir::coverage::{CounterId, MappedExpressionIndex};
|
||||
use rustc_middle::mir::coverage::{CounterId, ExpressionId, Operand};
|
||||
|
||||
/// Must match the layout of `LLVMRustCounterKind`.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
@ -30,11 +30,8 @@ pub struct Counter {
|
||||
}
|
||||
|
||||
impl Counter {
|
||||
/// Constructs a new `Counter` of kind `Zero`. For this `CounterKind`, the
|
||||
/// `id` is not used.
|
||||
pub fn zero() -> Self {
|
||||
Self { kind: CounterKind::Zero, id: 0 }
|
||||
}
|
||||
/// A `Counter` of kind `Zero`. For this counter kind, the `id` is not used.
|
||||
pub(crate) const ZERO: Self = Self { kind: CounterKind::Zero, id: 0 };
|
||||
|
||||
/// Constructs a new `Counter` of kind `CounterValueReference`.
|
||||
pub fn counter_value_reference(counter_id: CounterId) -> Self {
|
||||
@ -42,20 +39,16 @@ impl Counter {
|
||||
}
|
||||
|
||||
/// Constructs a new `Counter` of kind `Expression`.
|
||||
pub fn expression(mapped_expression_index: MappedExpressionIndex) -> Self {
|
||||
Self { kind: CounterKind::Expression, id: mapped_expression_index.into() }
|
||||
pub(crate) fn expression(expression_id: ExpressionId) -> Self {
|
||||
Self { kind: CounterKind::Expression, id: expression_id.as_u32() }
|
||||
}
|
||||
|
||||
/// Returns true if the `Counter` kind is `Zero`.
|
||||
pub fn is_zero(&self) -> bool {
|
||||
matches!(self.kind, CounterKind::Zero)
|
||||
}
|
||||
|
||||
/// An explicitly-named function to get the ID value, making it more obvious
|
||||
/// that the stored value is now 0-based.
|
||||
pub fn zero_based_id(&self) -> u32 {
|
||||
debug_assert!(!self.is_zero(), "`id` is undefined for CounterKind::Zero");
|
||||
self.id
|
||||
pub(crate) fn from_operand(operand: Operand) -> Self {
|
||||
match operand {
|
||||
Operand::Zero => Self::ZERO,
|
||||
Operand::Counter(id) => Self::counter_value_reference(id),
|
||||
Operand::Expression(id) => Self::expression(id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,6 +74,11 @@ pub struct CounterExpression {
|
||||
}
|
||||
|
||||
impl CounterExpression {
|
||||
/// The dummy expression `(0 - 0)` has a representation of all zeroes,
|
||||
/// making it marginally more efficient to initialize than `(0 + 0)`.
|
||||
pub(crate) const DUMMY: Self =
|
||||
Self { lhs: Counter::ZERO, kind: ExprKind::Subtract, rhs: Counter::ZERO };
|
||||
|
||||
pub fn new(lhs: Counter, kind: ExprKind, rhs: Counter) -> Self {
|
||||
Self { kind, lhs, rhs }
|
||||
}
|
||||
@ -172,7 +170,7 @@ impl CounterMappingRegion {
|
||||
) -> Self {
|
||||
Self {
|
||||
counter,
|
||||
false_counter: Counter::zero(),
|
||||
false_counter: Counter::ZERO,
|
||||
file_id,
|
||||
expanded_file_id: 0,
|
||||
start_line,
|
||||
@ -220,8 +218,8 @@ impl CounterMappingRegion {
|
||||
end_col: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
counter: Counter::zero(),
|
||||
false_counter: Counter::zero(),
|
||||
counter: Counter::ZERO,
|
||||
false_counter: Counter::ZERO,
|
||||
file_id,
|
||||
expanded_file_id,
|
||||
start_line,
|
||||
@ -243,8 +241,8 @@ impl CounterMappingRegion {
|
||||
end_col: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
counter: Counter::zero(),
|
||||
false_counter: Counter::zero(),
|
||||
counter: Counter::ZERO,
|
||||
false_counter: Counter::ZERO,
|
||||
file_id,
|
||||
expanded_file_id: 0,
|
||||
start_line,
|
||||
@ -268,7 +266,7 @@ impl CounterMappingRegion {
|
||||
) -> Self {
|
||||
Self {
|
||||
counter,
|
||||
false_counter: Counter::zero(),
|
||||
false_counter: Counter::ZERO,
|
||||
file_id,
|
||||
expanded_file_id: 0,
|
||||
start_line,
|
||||
|
@ -1,10 +1,8 @@
|
||||
use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind};
|
||||
|
||||
use rustc_index::{IndexSlice, IndexVec};
|
||||
use rustc_middle::bug;
|
||||
use rustc_middle::mir::coverage::{
|
||||
CodeRegion, CounterId, ExpressionId, MappedExpressionIndex, Op, Operand,
|
||||
};
|
||||
use rustc_data_structures::fx::FxIndexSet;
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir::coverage::{CodeRegion, CounterId, ExpressionId, Op, Operand};
|
||||
use rustc_middle::ty::Instance;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
@ -128,6 +126,58 @@ impl<'tcx> FunctionCoverage<'tcx> {
|
||||
self.unreachable_regions.push(region)
|
||||
}
|
||||
|
||||
/// Perform some simplifications to make the final coverage mappings
|
||||
/// slightly smaller.
|
||||
///
|
||||
/// This method mainly exists to preserve the simplifications that were
|
||||
/// already being performed by the Rust-side expression renumbering, so that
|
||||
/// the resulting coverage mappings don't get worse.
|
||||
pub(crate) fn simplify_expressions(&mut self) {
|
||||
// The set of expressions that either were optimized out entirely, or
|
||||
// have zero as both of their operands, and will therefore always have
|
||||
// a value of zero. Other expressions that refer to these as operands
|
||||
// can have those operands replaced with `Operand::Zero`.
|
||||
let mut zero_expressions = FxIndexSet::default();
|
||||
|
||||
// For each expression, perform simplifications based on lower-numbered
|
||||
// expressions, and then update the set of always-zero expressions if
|
||||
// necessary.
|
||||
// (By construction, expressions can only refer to other expressions
|
||||
// that have lower IDs, so one simplification pass is sufficient.)
|
||||
for (id, maybe_expression) in self.expressions.iter_enumerated_mut() {
|
||||
let Some(expression) = maybe_expression else {
|
||||
// If an expression is missing, it must have been optimized away,
|
||||
// so any operand that refers to it can be replaced with zero.
|
||||
zero_expressions.insert(id);
|
||||
continue;
|
||||
};
|
||||
|
||||
// If an operand refers to an expression that is always zero, then
|
||||
// that operand can be replaced with `Operand::Zero`.
|
||||
let maybe_set_operand_to_zero = |operand: &mut Operand| match &*operand {
|
||||
Operand::Expression(id) if zero_expressions.contains(id) => {
|
||||
*operand = Operand::Zero;
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
maybe_set_operand_to_zero(&mut expression.lhs);
|
||||
maybe_set_operand_to_zero(&mut expression.rhs);
|
||||
|
||||
// Coverage counter values cannot be negative, so if an expression
|
||||
// involves subtraction from zero, assume that its RHS must also be zero.
|
||||
// (Do this after simplifications that could set the LHS to zero.)
|
||||
if let Expression { lhs: Operand::Zero, op: Op::Subtract, .. } = expression {
|
||||
expression.rhs = Operand::Zero;
|
||||
}
|
||||
|
||||
// After the above simplifications, if both operands are zero, then
|
||||
// we know that this expression is always zero too.
|
||||
if let Expression { lhs: Operand::Zero, rhs: Operand::Zero, .. } = expression {
|
||||
zero_expressions.insert(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the source hash, generated from the HIR node structure, and used to indicate whether
|
||||
/// or not the source code structure changed between different compilations.
|
||||
pub fn source_hash(&self) -> u64 {
|
||||
@ -146,8 +196,14 @@ impl<'tcx> FunctionCoverage<'tcx> {
|
||||
self.instance
|
||||
);
|
||||
|
||||
let counter_expressions = self.counter_expressions();
|
||||
// Expression IDs are indices into `self.expressions`, and on the LLVM
|
||||
// side they will be treated as indices into `counter_expressions`, so
|
||||
// the two vectors should correspond 1:1.
|
||||
assert_eq!(self.expressions.len(), counter_expressions.len());
|
||||
|
||||
let counter_regions = self.counter_regions();
|
||||
let (counter_expressions, expression_regions) = self.expressions_with_regions();
|
||||
let expression_regions = self.expression_regions();
|
||||
let unreachable_regions = self.unreachable_regions();
|
||||
|
||||
let counter_regions =
|
||||
@ -163,149 +219,53 @@ impl<'tcx> FunctionCoverage<'tcx> {
|
||||
})
|
||||
}
|
||||
|
||||
fn expressions_with_regions(
|
||||
&self,
|
||||
) -> (Vec<CounterExpression>, impl Iterator<Item = (Counter, &CodeRegion)>) {
|
||||
let mut counter_expressions = Vec::with_capacity(self.expressions.len());
|
||||
let mut expression_regions = Vec::with_capacity(self.expressions.len());
|
||||
let mut new_indexes = IndexVec::from_elem_n(None, self.expressions.len());
|
||||
/// Convert this function's coverage expression data into a form that can be
|
||||
/// passed through FFI to LLVM.
|
||||
fn counter_expressions(&self) -> Vec<CounterExpression> {
|
||||
// We know that LLVM will optimize out any unused expressions before
|
||||
// producing the final coverage map, so there's no need to do the same
|
||||
// thing on the Rust side unless we're confident we can do much better.
|
||||
// (See `CounterExpressionsMinimizer` in `CoverageMappingWriter.cpp`.)
|
||||
|
||||
// This closure converts any `Expression` operand (`lhs` or `rhs` of the `Op::Add` or
|
||||
// `Op::Subtract` operation) into its native `llvm::coverage::Counter::CounterKind` type
|
||||
// and value.
|
||||
//
|
||||
// Expressions will be returned from this function in a sequential vector (array) of
|
||||
// `CounterExpression`, so the expression IDs must be mapped from their original,
|
||||
// potentially sparse set of indexes.
|
||||
//
|
||||
// An `Expression` as an operand will have already been encountered as an `Expression` with
|
||||
// operands, so its new_index will already have been generated (as a 1-up index value).
|
||||
// (If an `Expression` as an operand does not have a corresponding new_index, it was
|
||||
// probably optimized out, after the expression was injected into the MIR, so it will
|
||||
// get a `CounterKind::Zero` instead.)
|
||||
//
|
||||
// In other words, an `Expression`s at any given index can include other expressions as
|
||||
// operands, but expression operands can only come from the subset of expressions having
|
||||
// `expression_index`s lower than the referencing `Expression`. Therefore, it is
|
||||
// reasonable to look up the new index of an expression operand while the `new_indexes`
|
||||
// vector is only complete up to the current `ExpressionIndex`.
|
||||
type NewIndexes = IndexSlice<ExpressionId, Option<MappedExpressionIndex>>;
|
||||
let id_to_counter = |new_indexes: &NewIndexes, operand: Operand| match operand {
|
||||
Operand::Zero => Some(Counter::zero()),
|
||||
Operand::Counter(id) => Some(Counter::counter_value_reference(id)),
|
||||
Operand::Expression(id) => {
|
||||
self.expressions
|
||||
.get(id)
|
||||
.expect("expression id is out of range")
|
||||
.as_ref()
|
||||
// If an expression was optimized out, assume it would have produced a count
|
||||
// of zero. This ensures that expressions dependent on optimized-out
|
||||
// expressions are still valid.
|
||||
.map_or(Some(Counter::zero()), |_| new_indexes[id].map(Counter::expression))
|
||||
}
|
||||
};
|
||||
|
||||
for (original_index, expression) in
|
||||
self.expressions.iter_enumerated().filter_map(|(original_index, entry)| {
|
||||
// Option::map() will return None to filter out missing expressions. This may happen
|
||||
// if, for example, a MIR-instrumented expression is removed during an optimization.
|
||||
entry.as_ref().map(|expression| (original_index, expression))
|
||||
self.expressions
|
||||
.iter()
|
||||
.map(|expression| match expression {
|
||||
None => {
|
||||
// This expression ID was allocated, but we never saw the
|
||||
// actual expression, so it must have been optimized out.
|
||||
// Replace it with a dummy expression, and let LLVM take
|
||||
// care of omitting it from the expression list.
|
||||
CounterExpression::DUMMY
|
||||
}
|
||||
&Some(Expression { lhs, op, rhs, .. }) => {
|
||||
// Convert the operands and operator as normal.
|
||||
CounterExpression::new(
|
||||
Counter::from_operand(lhs),
|
||||
match op {
|
||||
Op::Add => ExprKind::Add,
|
||||
Op::Subtract => ExprKind::Subtract,
|
||||
},
|
||||
Counter::from_operand(rhs),
|
||||
)
|
||||
}
|
||||
})
|
||||
{
|
||||
let optional_region = &expression.region;
|
||||
let Expression { lhs, op, rhs, .. } = *expression;
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
if let Some(Some((lhs_counter, mut rhs_counter))) = id_to_counter(&new_indexes, lhs)
|
||||
.map(|lhs_counter| {
|
||||
id_to_counter(&new_indexes, rhs).map(|rhs_counter| (lhs_counter, rhs_counter))
|
||||
})
|
||||
{
|
||||
if lhs_counter.is_zero() && op.is_subtract() {
|
||||
// The left side of a subtraction was probably optimized out. As an example,
|
||||
// a branch condition might be evaluated as a constant expression, and the
|
||||
// branch could be removed, dropping unused counters in the process.
|
||||
//
|
||||
// Since counters are unsigned, we must assume the result of the expression
|
||||
// can be no more and no less than zero. An expression known to evaluate to zero
|
||||
// does not need to be added to the coverage map.
|
||||
//
|
||||
// Coverage test `loops_branches.rs` includes multiple variations of branches
|
||||
// based on constant conditional (literal `true` or `false`), and demonstrates
|
||||
// that the expected counts are still correct.
|
||||
debug!(
|
||||
"Expression subtracts from zero (assume unreachable): \
|
||||
original_index={:?}, lhs={:?}, op={:?}, rhs={:?}, region={:?}",
|
||||
original_index, lhs, op, rhs, optional_region,
|
||||
);
|
||||
rhs_counter = Counter::zero();
|
||||
}
|
||||
debug_assert!(
|
||||
lhs_counter.is_zero()
|
||||
// Note: with `as usize` the ID _could_ overflow/wrap if `usize = u16`
|
||||
|| ((lhs_counter.zero_based_id() as usize)
|
||||
<= usize::max(self.counters.len(), self.expressions.len())),
|
||||
"lhs id={} > both counters.len()={} and expressions.len()={}
|
||||
({:?} {:?} {:?})",
|
||||
lhs_counter.zero_based_id(),
|
||||
self.counters.len(),
|
||||
self.expressions.len(),
|
||||
lhs_counter,
|
||||
op,
|
||||
rhs_counter,
|
||||
);
|
||||
|
||||
debug_assert!(
|
||||
rhs_counter.is_zero()
|
||||
// Note: with `as usize` the ID _could_ overflow/wrap if `usize = u16`
|
||||
|| ((rhs_counter.zero_based_id() as usize)
|
||||
<= usize::max(self.counters.len(), self.expressions.len())),
|
||||
"rhs id={} > both counters.len()={} and expressions.len()={}
|
||||
({:?} {:?} {:?})",
|
||||
rhs_counter.zero_based_id(),
|
||||
self.counters.len(),
|
||||
self.expressions.len(),
|
||||
lhs_counter,
|
||||
op,
|
||||
rhs_counter,
|
||||
);
|
||||
|
||||
// Both operands exist. `Expression` operands exist in `self.expressions` and have
|
||||
// been assigned a `new_index`.
|
||||
let mapped_expression_index =
|
||||
MappedExpressionIndex::from(counter_expressions.len());
|
||||
let expression = CounterExpression::new(
|
||||
lhs_counter,
|
||||
match op {
|
||||
Op::Add => ExprKind::Add,
|
||||
Op::Subtract => ExprKind::Subtract,
|
||||
},
|
||||
rhs_counter,
|
||||
);
|
||||
debug!(
|
||||
"Adding expression {:?} = {:?}, region: {:?}",
|
||||
mapped_expression_index, expression, optional_region
|
||||
);
|
||||
counter_expressions.push(expression);
|
||||
new_indexes[original_index] = Some(mapped_expression_index);
|
||||
if let Some(region) = optional_region {
|
||||
expression_regions.push((Counter::expression(mapped_expression_index), region));
|
||||
}
|
||||
} else {
|
||||
bug!(
|
||||
"expression has one or more missing operands \
|
||||
original_index={:?}, lhs={:?}, op={:?}, rhs={:?}, region={:?}",
|
||||
original_index,
|
||||
lhs,
|
||||
op,
|
||||
rhs,
|
||||
optional_region,
|
||||
);
|
||||
}
|
||||
}
|
||||
(counter_expressions, expression_regions.into_iter())
|
||||
fn expression_regions(&self) -> Vec<(Counter, &CodeRegion)> {
|
||||
// Find all of the expression IDs that weren't optimized out AND have
|
||||
// an attached code region, and return the corresponding mapping as a
|
||||
// counter/region pair.
|
||||
self.expressions
|
||||
.iter_enumerated()
|
||||
.filter_map(|(id, expression)| {
|
||||
let code_region = expression.as_ref()?.region.as_ref()?;
|
||||
Some((Counter::expression(id), code_region))
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn unreachable_regions(&self) -> impl Iterator<Item = (Counter, &CodeRegion)> {
|
||||
self.unreachable_regions.iter().map(|region| (Counter::zero(), region))
|
||||
self.unreachable_regions.iter().map(|region| (Counter::ZERO, region))
|
||||
}
|
||||
}
|
||||
|
@ -60,8 +60,11 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) {
|
||||
|
||||
// Encode coverage mappings and generate function records
|
||||
let mut function_data = Vec::new();
|
||||
for (instance, function_coverage) in function_coverage_map {
|
||||
for (instance, mut function_coverage) in function_coverage_map {
|
||||
debug!("Generate function coverage for {}, {:?}", cx.codegen_unit.name(), instance);
|
||||
function_coverage.simplify_expressions();
|
||||
let function_coverage = function_coverage;
|
||||
|
||||
let mangled_function_name = tcx.symbol_name(instance).name;
|
||||
let source_hash = function_coverage.source_hash();
|
||||
let is_used = function_coverage.is_used();
|
||||
|
@ -660,12 +660,12 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
|
||||
}
|
||||
_ => match ct.ty().kind() {
|
||||
ty::Int(ity) => {
|
||||
let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty());
|
||||
let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all());
|
||||
let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
|
||||
write!(output, "{val}")
|
||||
}
|
||||
ty::Uint(_) => {
|
||||
let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty());
|
||||
let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all());
|
||||
write!(output, "{val}")
|
||||
}
|
||||
ty::Bool => {
|
||||
|
@ -1098,8 +1098,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
InlineAsmOperandRef::Const { string }
|
||||
}
|
||||
mir::InlineAsmOperand::SymFn { ref value } => {
|
||||
let literal = self.monomorphize(value.literal);
|
||||
if let ty::FnDef(def_id, args) = *literal.ty().kind() {
|
||||
let const_ = self.monomorphize(value.const_);
|
||||
if let ty::FnDef(def_id, args) = *const_.ty().kind() {
|
||||
let instance = ty::Instance::resolve_for_fn_ptr(
|
||||
bx.tcx(),
|
||||
ty::ParamEnv::reveal_all(),
|
||||
|
@ -13,37 +13,37 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
pub fn eval_mir_constant_to_operand(
|
||||
&self,
|
||||
bx: &mut Bx,
|
||||
constant: &mir::Constant<'tcx>,
|
||||
constant: &mir::ConstOperand<'tcx>,
|
||||
) -> OperandRef<'tcx, Bx::Value> {
|
||||
let val = self.eval_mir_constant(constant);
|
||||
let ty = self.monomorphize(constant.ty());
|
||||
OperandRef::from_const(bx, val, ty)
|
||||
}
|
||||
|
||||
pub fn eval_mir_constant(&self, constant: &mir::Constant<'tcx>) -> mir::ConstValue<'tcx> {
|
||||
self.monomorphize(constant.literal)
|
||||
pub fn eval_mir_constant(&self, constant: &mir::ConstOperand<'tcx>) -> mir::ConstValue<'tcx> {
|
||||
self.monomorphize(constant.const_)
|
||||
.eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span))
|
||||
.expect("erroneous constant not captured by required_consts")
|
||||
}
|
||||
|
||||
/// This is a convenience helper for `simd_shuffle_indices`. It has the precondition
|
||||
/// that the given `constant` is an `ConstantKind::Unevaluated` and must be convertible to
|
||||
/// that the given `constant` is an `Const::Unevaluated` and must be convertible to
|
||||
/// a `ValTree`. If you want a more general version of this, talk to `wg-const-eval` on zulip.
|
||||
///
|
||||
/// Note that this function is cursed, since usually MIR consts should not be evaluated to valtrees!
|
||||
pub fn eval_unevaluated_mir_constant_to_valtree(
|
||||
&self,
|
||||
constant: &mir::Constant<'tcx>,
|
||||
constant: &mir::ConstOperand<'tcx>,
|
||||
) -> Result<Option<ty::ValTree<'tcx>>, ErrorHandled> {
|
||||
let uv = match self.monomorphize(constant.literal) {
|
||||
mir::ConstantKind::Unevaluated(uv, _) => uv.shrink(),
|
||||
mir::ConstantKind::Ty(c) => match c.kind() {
|
||||
let uv = match self.monomorphize(constant.const_) {
|
||||
mir::Const::Unevaluated(uv, _) => uv.shrink(),
|
||||
mir::Const::Ty(c) => match c.kind() {
|
||||
// A constant that came from a const generic but was then used as an argument to old-style
|
||||
// simd_shuffle (passing as argument instead of as a generic param).
|
||||
rustc_type_ir::ConstKind::Value(valtree) => return Ok(Some(valtree)),
|
||||
other => span_bug!(constant.span, "{other:#?}"),
|
||||
},
|
||||
// We should never encounter `ConstantKind::Val` unless MIR opts (like const prop) evaluate
|
||||
// We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate
|
||||
// a constant and write that value back into `Operand`s. This could happen, but is unlikely.
|
||||
// Also: all users of `simd_shuffle` are on unstable and already need to take a lot of care
|
||||
// around intrinsics. For an issue to happen here, it would require a macro expanding to a
|
||||
@ -65,7 +65,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
pub fn simd_shuffle_indices(
|
||||
&mut self,
|
||||
bx: &Bx,
|
||||
constant: &mir::Constant<'tcx>,
|
||||
constant: &mir::ConstOperand<'tcx>,
|
||||
) -> (Bx::Value, Ty<'tcx>) {
|
||||
let ty = self.monomorphize(constant.ty());
|
||||
let val = self
|
||||
|
@ -3,7 +3,7 @@ use rustc_hir::{LangItem, CRATE_HIR_ID};
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::interpret::PointerArithmetic;
|
||||
use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_session::lint::builtin::INVALID_ALIGNMENT;
|
||||
use std::borrow::Borrow;
|
||||
use std::hash::Hash;
|
||||
@ -596,7 +596,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
|
||||
_bin_op: mir::BinOp,
|
||||
_left: &ImmTy<'tcx>,
|
||||
_right: &ImmTy<'tcx>,
|
||||
) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
|
||||
) -> InterpResult<'tcx, (ImmTy<'tcx>, bool)> {
|
||||
throw_unsup_format!("pointer arithmetic or comparison is not supported at compile-time");
|
||||
}
|
||||
|
||||
|
@ -24,41 +24,44 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
cast_ty: Ty<'tcx>,
|
||||
dest: &PlaceTy<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx> {
|
||||
// `cast_ty` will often be the same as `dest.ty`, but not always, since subtyping is still
|
||||
// possible.
|
||||
let cast_layout =
|
||||
if cast_ty == dest.layout.ty { dest.layout } else { self.layout_of(cast_ty)? };
|
||||
// FIXME: In which cases should we trigger UB when the source is uninit?
|
||||
match cast_kind {
|
||||
CastKind::PointerCoercion(PointerCoercion::Unsize) => {
|
||||
let cast_ty = self.layout_of(cast_ty)?;
|
||||
self.unsize_into(src, cast_ty, dest)?;
|
||||
self.unsize_into(src, cast_layout, dest)?;
|
||||
}
|
||||
|
||||
CastKind::PointerExposeAddress => {
|
||||
let src = self.read_immediate(src)?;
|
||||
let res = self.pointer_expose_address_cast(&src, cast_ty)?;
|
||||
self.write_immediate(res, dest)?;
|
||||
let res = self.pointer_expose_address_cast(&src, cast_layout)?;
|
||||
self.write_immediate(*res, dest)?;
|
||||
}
|
||||
|
||||
CastKind::PointerFromExposedAddress => {
|
||||
let src = self.read_immediate(src)?;
|
||||
let res = self.pointer_from_exposed_address_cast(&src, cast_ty)?;
|
||||
self.write_immediate(res, dest)?;
|
||||
let res = self.pointer_from_exposed_address_cast(&src, cast_layout)?;
|
||||
self.write_immediate(*res, dest)?;
|
||||
}
|
||||
|
||||
CastKind::IntToInt | CastKind::IntToFloat => {
|
||||
let src = self.read_immediate(src)?;
|
||||
let res = self.int_to_int_or_float(&src, cast_ty)?;
|
||||
self.write_immediate(res, dest)?;
|
||||
let res = self.int_to_int_or_float(&src, cast_layout)?;
|
||||
self.write_immediate(*res, dest)?;
|
||||
}
|
||||
|
||||
CastKind::FloatToFloat | CastKind::FloatToInt => {
|
||||
let src = self.read_immediate(src)?;
|
||||
let res = self.float_to_float_or_int(&src, cast_ty)?;
|
||||
self.write_immediate(res, dest)?;
|
||||
let res = self.float_to_float_or_int(&src, cast_layout)?;
|
||||
self.write_immediate(*res, dest)?;
|
||||
}
|
||||
|
||||
CastKind::FnPtrToPtr | CastKind::PtrToPtr => {
|
||||
let src = self.read_immediate(src)?;
|
||||
let res = self.ptr_to_ptr(&src, cast_ty)?;
|
||||
self.write_immediate(res, dest)?;
|
||||
let res = self.ptr_to_ptr(&src, cast_layout)?;
|
||||
self.write_immediate(*res, dest)?;
|
||||
}
|
||||
|
||||
CastKind::PointerCoercion(
|
||||
@ -87,7 +90,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
let fn_ptr = self.fn_ptr(FnVal::Instance(instance));
|
||||
self.write_pointer(fn_ptr, dest)?;
|
||||
}
|
||||
_ => span_bug!(self.cur_span(), "reify fn pointer on {:?}", src.layout.ty),
|
||||
_ => span_bug!(self.cur_span(), "reify fn pointer on {}", src.layout.ty),
|
||||
}
|
||||
}
|
||||
|
||||
@ -98,7 +101,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
// No change to value
|
||||
self.write_immediate(*src, dest)?;
|
||||
}
|
||||
_ => span_bug!(self.cur_span(), "fn to unsafe fn cast on {:?}", cast_ty),
|
||||
_ => span_bug!(self.cur_span(), "fn to unsafe fn cast on {}", cast_ty),
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,7 +122,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
let fn_ptr = self.fn_ptr(FnVal::Instance(instance));
|
||||
self.write_pointer(fn_ptr, dest)?;
|
||||
}
|
||||
_ => span_bug!(self.cur_span(), "closure fn pointer on {:?}", src.layout.ty),
|
||||
_ => span_bug!(self.cur_span(), "closure fn pointer on {}", src.layout.ty),
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,6 +143,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
CastKind::Transmute => {
|
||||
assert!(src.layout.is_sized());
|
||||
assert!(dest.layout.is_sized());
|
||||
assert_eq!(cast_ty, dest.layout.ty); // we otherwise ignore `cast_ty` enirely...
|
||||
if src.layout.size != dest.layout.size {
|
||||
let src_bytes = src.layout.size.bytes();
|
||||
let dest_bytes = dest.layout.size.bytes();
|
||||
@ -164,62 +168,61 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
pub fn int_to_int_or_float(
|
||||
&self,
|
||||
src: &ImmTy<'tcx, M::Provenance>,
|
||||
cast_ty: Ty<'tcx>,
|
||||
) -> InterpResult<'tcx, Immediate<M::Provenance>> {
|
||||
cast_to: TyAndLayout<'tcx>,
|
||||
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
|
||||
assert!(src.layout.ty.is_integral() || src.layout.ty.is_char() || src.layout.ty.is_bool());
|
||||
assert!(cast_ty.is_floating_point() || cast_ty.is_integral() || cast_ty.is_char());
|
||||
assert!(cast_to.ty.is_floating_point() || cast_to.ty.is_integral() || cast_to.ty.is_char());
|
||||
|
||||
Ok(self.cast_from_int_like(src.to_scalar(), src.layout, cast_ty)?.into())
|
||||
Ok(ImmTy::from_scalar(
|
||||
self.cast_from_int_like(src.to_scalar(), src.layout, cast_to.ty)?,
|
||||
cast_to,
|
||||
))
|
||||
}
|
||||
|
||||
/// Handles 'FloatToFloat' and 'FloatToInt' casts.
|
||||
pub fn float_to_float_or_int(
|
||||
&self,
|
||||
src: &ImmTy<'tcx, M::Provenance>,
|
||||
cast_ty: Ty<'tcx>,
|
||||
) -> InterpResult<'tcx, Immediate<M::Provenance>> {
|
||||
cast_to: TyAndLayout<'tcx>,
|
||||
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
|
||||
use rustc_type_ir::sty::TyKind::*;
|
||||
|
||||
match src.layout.ty.kind() {
|
||||
let val = match src.layout.ty.kind() {
|
||||
// Floating point
|
||||
Float(FloatTy::F32) => {
|
||||
return Ok(self.cast_from_float(src.to_scalar().to_f32()?, cast_ty).into());
|
||||
}
|
||||
Float(FloatTy::F64) => {
|
||||
return Ok(self.cast_from_float(src.to_scalar().to_f64()?, cast_ty).into());
|
||||
}
|
||||
Float(FloatTy::F32) => self.cast_from_float(src.to_scalar().to_f32()?, cast_to.ty),
|
||||
Float(FloatTy::F64) => self.cast_from_float(src.to_scalar().to_f64()?, cast_to.ty),
|
||||
_ => {
|
||||
bug!("Can't cast 'Float' type into {:?}", cast_ty);
|
||||
bug!("Can't cast 'Float' type into {}", cast_to.ty);
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(ImmTy::from_scalar(val, cast_to))
|
||||
}
|
||||
|
||||
/// Handles 'FnPtrToPtr' and 'PtrToPtr' casts.
|
||||
pub fn ptr_to_ptr(
|
||||
&self,
|
||||
src: &ImmTy<'tcx, M::Provenance>,
|
||||
cast_ty: Ty<'tcx>,
|
||||
) -> InterpResult<'tcx, Immediate<M::Provenance>> {
|
||||
cast_to: TyAndLayout<'tcx>,
|
||||
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
|
||||
assert!(src.layout.ty.is_any_ptr());
|
||||
assert!(cast_ty.is_unsafe_ptr());
|
||||
assert!(cast_to.ty.is_unsafe_ptr());
|
||||
// Handle casting any ptr to raw ptr (might be a fat ptr).
|
||||
let dest_layout = self.layout_of(cast_ty)?;
|
||||
if dest_layout.size == src.layout.size {
|
||||
if cast_to.size == src.layout.size {
|
||||
// Thin or fat pointer that just hast the ptr kind of target type changed.
|
||||
return Ok(**src);
|
||||
return Ok(ImmTy::from_immediate(**src, cast_to));
|
||||
} else {
|
||||
// Casting the metadata away from a fat ptr.
|
||||
assert_eq!(src.layout.size, 2 * self.pointer_size());
|
||||
assert_eq!(dest_layout.size, self.pointer_size());
|
||||
assert_eq!(cast_to.size, self.pointer_size());
|
||||
assert!(src.layout.ty.is_unsafe_ptr());
|
||||
return match **src {
|
||||
Immediate::ScalarPair(data, _) => Ok(data.into()),
|
||||
Immediate::ScalarPair(data, _) => Ok(ImmTy::from_scalar(data, cast_to)),
|
||||
Immediate::Scalar(..) => span_bug!(
|
||||
self.cur_span(),
|
||||
"{:?} input to a fat-to-thin cast ({:?} -> {:?})",
|
||||
"{:?} input to a fat-to-thin cast ({} -> {})",
|
||||
*src,
|
||||
src.layout.ty,
|
||||
cast_ty
|
||||
cast_to.ty
|
||||
),
|
||||
Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)),
|
||||
};
|
||||
@ -229,10 +232,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
pub fn pointer_expose_address_cast(
|
||||
&mut self,
|
||||
src: &ImmTy<'tcx, M::Provenance>,
|
||||
cast_ty: Ty<'tcx>,
|
||||
) -> InterpResult<'tcx, Immediate<M::Provenance>> {
|
||||
cast_to: TyAndLayout<'tcx>,
|
||||
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
|
||||
assert_matches!(src.layout.ty.kind(), ty::RawPtr(_) | ty::FnPtr(_));
|
||||
assert!(cast_ty.is_integral());
|
||||
assert!(cast_to.ty.is_integral());
|
||||
|
||||
let scalar = src.to_scalar();
|
||||
let ptr = scalar.to_pointer(self)?;
|
||||
@ -240,16 +243,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
Ok(ptr) => M::expose_ptr(self, ptr)?,
|
||||
Err(_) => {} // Do nothing, exposing an invalid pointer (`None` provenance) is a NOP.
|
||||
};
|
||||
Ok(self.cast_from_int_like(scalar, src.layout, cast_ty)?.into())
|
||||
Ok(ImmTy::from_scalar(self.cast_from_int_like(scalar, src.layout, cast_to.ty)?, cast_to))
|
||||
}
|
||||
|
||||
pub fn pointer_from_exposed_address_cast(
|
||||
&self,
|
||||
src: &ImmTy<'tcx, M::Provenance>,
|
||||
cast_ty: Ty<'tcx>,
|
||||
) -> InterpResult<'tcx, Immediate<M::Provenance>> {
|
||||
cast_to: TyAndLayout<'tcx>,
|
||||
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
|
||||
assert!(src.layout.ty.is_integral());
|
||||
assert_matches!(cast_ty.kind(), ty::RawPtr(_));
|
||||
assert_matches!(cast_to.ty.kind(), ty::RawPtr(_));
|
||||
|
||||
// First cast to usize.
|
||||
let scalar = src.to_scalar();
|
||||
@ -258,12 +261,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
|
||||
// Then turn address into pointer.
|
||||
let ptr = M::ptr_from_addr_cast(&self, addr)?;
|
||||
Ok(Scalar::from_maybe_pointer(ptr, self).into())
|
||||
Ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(ptr, self), cast_to))
|
||||
}
|
||||
|
||||
/// Low-level cast helper function. This works directly on scalars and can take 'int-like' input
|
||||
/// type (basically everything with a scalar layout) to int/float/char types.
|
||||
pub fn cast_from_int_like(
|
||||
fn cast_from_int_like(
|
||||
&self,
|
||||
scalar: Scalar<M::Provenance>, // input value (there is no ScalarTy so we separate data+layout)
|
||||
src_layout: TyAndLayout<'tcx>,
|
||||
@ -298,7 +301,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
}
|
||||
|
||||
// Casts to bool are not permitted by rustc, no need to handle them here.
|
||||
_ => span_bug!(self.cur_span(), "invalid int to {:?} cast", cast_ty),
|
||||
_ => span_bug!(self.cur_span(), "invalid int to {} cast", cast_ty),
|
||||
})
|
||||
}
|
||||
|
||||
@ -331,7 +334,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
// float -> f64
|
||||
Float(FloatTy::F64) => Scalar::from_f64(f.convert(&mut false).value),
|
||||
// That's it.
|
||||
_ => span_bug!(self.cur_span(), "invalid float to {:?} cast", dest_ty),
|
||||
_ => span_bug!(self.cur_span(), "invalid float to {} cast", dest_ty),
|
||||
}
|
||||
}
|
||||
|
||||
@ -390,7 +393,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
|
||||
span_bug!(
|
||||
self.cur_span(),
|
||||
"invalid pointer unsizing {:?} -> {:?}",
|
||||
"invalid pointer unsizing {} -> {}",
|
||||
src.layout.ty,
|
||||
cast_ty
|
||||
)
|
||||
@ -404,7 +407,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
cast_ty: TyAndLayout<'tcx>,
|
||||
dest: &PlaceTy<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx> {
|
||||
trace!("Unsizing {:?} of type {} into {:?}", *src, src.layout.ty, cast_ty.ty);
|
||||
trace!("Unsizing {:?} of type {} into {}", *src, src.layout.ty, cast_ty.ty);
|
||||
match (&src.layout.ty.kind(), &cast_ty.ty.kind()) {
|
||||
(&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(TypeAndMut { ty: c, .. }))
|
||||
| (&ty::RawPtr(TypeAndMut { ty: s, .. }), &ty::RawPtr(TypeAndMut { ty: c, .. })) => {
|
||||
|
@ -76,7 +76,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
|
||||
let variant_index_relative_val =
|
||||
ImmTy::from_uint(variant_index_relative, tag_layout);
|
||||
let tag_val = self.binary_op(
|
||||
let tag_val = self.wrapping_binary_op(
|
||||
mir::BinOp::Add,
|
||||
&variant_index_relative_val,
|
||||
&niche_start_val,
|
||||
@ -153,19 +153,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
// Figure out which discriminant and variant this corresponds to.
|
||||
let index = match *tag_encoding {
|
||||
TagEncoding::Direct => {
|
||||
let scalar = tag_val.to_scalar();
|
||||
// Generate a specific error if `tag_val` is not an integer.
|
||||
// (`tag_bits` itself is only used for error messages below.)
|
||||
let tag_bits = scalar
|
||||
let tag_bits = tag_val
|
||||
.to_scalar()
|
||||
.try_to_int()
|
||||
.map_err(|dbg_val| err_ub!(InvalidTag(dbg_val)))?
|
||||
.assert_bits(tag_layout.size);
|
||||
// Cast bits from tag layout to discriminant layout.
|
||||
// After the checks we did above, this cannot fail, as
|
||||
// discriminants are int-like.
|
||||
let discr_val =
|
||||
self.cast_from_int_like(scalar, tag_val.layout, discr_layout.ty).unwrap();
|
||||
let discr_bits = discr_val.assert_bits(discr_layout.size);
|
||||
let discr_val = self.int_to_int_or_float(&tag_val, discr_layout).unwrap();
|
||||
let discr_bits = discr_val.to_scalar().assert_bits(discr_layout.size);
|
||||
// Convert discriminant to variant index, and catch invalid discriminants.
|
||||
let index = match *ty.kind() {
|
||||
ty::Adt(adt, _) => {
|
||||
@ -208,7 +207,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
let tag_val = ImmTy::from_uint(tag_bits, tag_layout);
|
||||
let niche_start_val = ImmTy::from_uint(niche_start, tag_layout);
|
||||
let variant_index_relative_val =
|
||||
self.binary_op(mir::BinOp::Sub, &tag_val, &niche_start_val)?;
|
||||
self.wrapping_binary_op(mir::BinOp::Sub, &tag_val, &niche_start_val)?;
|
||||
let variant_index_relative =
|
||||
variant_index_relative_val.to_scalar().assert_bits(tag_val.layout.size);
|
||||
// Check if this is in the range that indicates an actual discriminant.
|
||||
|
@ -416,7 +416,7 @@ pub(super) fn from_known_layout<'tcx>(
|
||||
if !mir_assign_valid_types(tcx.tcx, param_env, check_layout, known_layout) {
|
||||
span_bug!(
|
||||
tcx.span,
|
||||
"expected type differs from actual type.\nexpected: {:?}\nactual: {:?}",
|
||||
"expected type differs from actual type.\nexpected: {}\nactual: {}",
|
||||
known_layout.ty,
|
||||
check_layout.ty,
|
||||
);
|
||||
@ -712,7 +712,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
|
||||
ty::Foreign(_) => Ok(None),
|
||||
|
||||
_ => span_bug!(self.cur_span(), "size_and_align_of::<{:?}> not supported", layout.ty),
|
||||
_ => span_bug!(self.cur_span(), "size_and_align_of::<{}> not supported", layout.ty),
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
@ -982,7 +982,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
|
||||
ty::Bound(..)
|
||||
| ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
|
||||
bug!("`is_very_trivially_sized` applied to unexpected type: {:?}", ty)
|
||||
bug!("`is_very_trivially_sized` applied to unexpected type: {}", ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1089,7 +1089,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
|
||||
pub fn eval_mir_constant(
|
||||
&self,
|
||||
val: &mir::ConstantKind<'tcx>,
|
||||
val: &mir::Const<'tcx>,
|
||||
span: Option<Span>,
|
||||
layout: Option<TyAndLayout<'tcx>>,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
||||
|
@ -307,7 +307,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
let dist = {
|
||||
// Addresses are unsigned, so this is a `usize` computation. We have to do the
|
||||
// overflow check separately anyway.
|
||||
let (val, overflowed, _ty) = {
|
||||
let (val, overflowed) = {
|
||||
let a_offset = ImmTy::from_uint(a_offset, usize_layout);
|
||||
let b_offset = ImmTy::from_uint(b_offset, usize_layout);
|
||||
self.overflowing_binary_op(BinOp::Sub, &a_offset, &b_offset)?
|
||||
@ -324,7 +324,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
// The signed form of the intrinsic allows this. If we interpret the
|
||||
// difference as isize, we'll get the proper signed difference. If that
|
||||
// seems *positive*, they were more than isize::MAX apart.
|
||||
let dist = val.to_target_isize(self)?;
|
||||
let dist = val.to_scalar().to_target_isize(self)?;
|
||||
if dist >= 0 {
|
||||
throw_ub_custom!(
|
||||
fluent::const_eval_offset_from_underflow,
|
||||
@ -334,7 +334,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
dist
|
||||
} else {
|
||||
// b >= a
|
||||
let dist = val.to_target_isize(self)?;
|
||||
let dist = val.to_scalar().to_target_isize(self)?;
|
||||
// If converting to isize produced a *negative* result, we had an overflow
|
||||
// because they were more than isize::MAX apart.
|
||||
if dist < 0 {
|
||||
@ -504,9 +504,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
// Performs an exact division, resulting in undefined behavior where
|
||||
// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`.
|
||||
// First, check x % y != 0 (or if that computation overflows).
|
||||
let (res, overflow, _ty) = self.overflowing_binary_op(BinOp::Rem, &a, &b)?;
|
||||
let (res, overflow) = self.overflowing_binary_op(BinOp::Rem, &a, &b)?;
|
||||
assert!(!overflow); // All overflow is UB, so this should never return on overflow.
|
||||
if res.assert_bits(a.layout.size) != 0 {
|
||||
if res.to_scalar().assert_bits(a.layout.size) != 0 {
|
||||
throw_ub_custom!(
|
||||
fluent::const_eval_exact_div_has_remainder,
|
||||
a = format!("{a}"),
|
||||
@ -524,7 +524,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
r: &ImmTy<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, Scalar<M::Provenance>> {
|
||||
assert!(matches!(mir_op, BinOp::Add | BinOp::Sub));
|
||||
let (val, overflowed, _ty) = self.overflowing_binary_op(mir_op, l, r)?;
|
||||
let (val, overflowed) = self.overflowing_binary_op(mir_op, l, r)?;
|
||||
Ok(if overflowed {
|
||||
let size = l.layout.size;
|
||||
let num_bits = size.bits();
|
||||
@ -556,7 +556,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val
|
||||
val.to_scalar()
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ use std::hash::Hash;
|
||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::ty::layout::TyAndLayout;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_target::abi::{Align, Size};
|
||||
use rustc_target::spec::abi::Abi as CallAbi;
|
||||
@ -18,7 +18,7 @@ use crate::const_eval::CheckAlignment;
|
||||
|
||||
use super::{
|
||||
AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, FnArg, Frame, ImmTy, InterpCx,
|
||||
InterpResult, MPlaceTy, MemoryKind, OpTy, PlaceTy, Pointer, Provenance, Scalar,
|
||||
InterpResult, MPlaceTy, MemoryKind, OpTy, PlaceTy, Pointer, Provenance,
|
||||
};
|
||||
|
||||
/// Data returned by Machine::stack_pop,
|
||||
@ -238,7 +238,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
|
||||
bin_op: mir::BinOp,
|
||||
left: &ImmTy<'tcx, Self::Provenance>,
|
||||
right: &ImmTy<'tcx, Self::Provenance>,
|
||||
) -> InterpResult<'tcx, (Scalar<Self::Provenance>, bool, Ty<'tcx>)>;
|
||||
) -> InterpResult<'tcx, (ImmTy<'tcx, Self::Provenance>, bool)>;
|
||||
|
||||
/// Called before writing the specified `local` of the `frame`.
|
||||
/// Since writing a ZST is not actually accessing memory or locals, this is never invoked
|
||||
|
@ -8,7 +8,7 @@ use either::{Either, Left, Right};
|
||||
use rustc_hir::def::Namespace;
|
||||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
|
||||
use rustc_middle::ty::{ConstInt, Ty};
|
||||
use rustc_middle::ty::{ConstInt, Ty, TyCtxt};
|
||||
use rustc_middle::{mir, ty};
|
||||
use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size};
|
||||
|
||||
@ -165,7 +165,15 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
|
||||
|
||||
#[inline(always)]
|
||||
pub fn from_immediate(imm: Immediate<Prov>, layout: TyAndLayout<'tcx>) -> Self {
|
||||
debug_assert!(layout.is_sized(), "immediates must be sized");
|
||||
debug_assert!(
|
||||
match (imm, layout.abi) {
|
||||
(Immediate::Scalar(..), Abi::Scalar(..)) => true,
|
||||
(Immediate::ScalarPair(..), Abi::ScalarPair(..)) => true,
|
||||
(Immediate::Uninit, _) if layout.is_sized() => true,
|
||||
_ => false,
|
||||
},
|
||||
"immediate {imm:?} does not fit to layout {layout:?}",
|
||||
);
|
||||
ImmTy { imm, layout }
|
||||
}
|
||||
|
||||
@ -194,6 +202,12 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
|
||||
Self::from_scalar(Scalar::from_int(i, layout.size), layout)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn from_bool(b: bool, tcx: TyCtxt<'tcx>) -> Self {
|
||||
let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(tcx.types.bool)).unwrap();
|
||||
Self::from_scalar(Scalar::from_bool(b), layout)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn to_const_int(self) -> ConstInt {
|
||||
assert!(self.layout.ty.is_integral());
|
||||
@ -448,7 +462,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
alloc_range(Size::ZERO, size),
|
||||
/*read_provenance*/ matches!(s, abi::Pointer(_)),
|
||||
)?;
|
||||
Some(ImmTy { imm: scalar.into(), layout: mplace.layout })
|
||||
Some(ImmTy::from_scalar(scalar, mplace.layout))
|
||||
}
|
||||
Abi::ScalarPair(
|
||||
abi::Scalar::Initialized { value: a, .. },
|
||||
@ -468,7 +482,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
alloc_range(b_offset, b_size),
|
||||
/*read_provenance*/ matches!(b, abi::Pointer(_)),
|
||||
)?;
|
||||
Some(ImmTy { imm: Immediate::ScalarPair(a_val, b_val), layout: mplace.layout })
|
||||
Some(ImmTy::from_immediate(Immediate::ScalarPair(a_val, b_val), mplace.layout))
|
||||
}
|
||||
_ => {
|
||||
// Neither a scalar nor scalar pair.
|
||||
@ -514,11 +528,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
Abi::Scalar(abi::Scalar::Initialized { .. })
|
||||
| Abi::ScalarPair(abi::Scalar::Initialized { .. }, abi::Scalar::Initialized { .. })
|
||||
) {
|
||||
span_bug!(
|
||||
self.cur_span(),
|
||||
"primitive read not possible for type: {:?}",
|
||||
op.layout().ty
|
||||
);
|
||||
span_bug!(self.cur_span(), "primitive read not possible for type: {}", op.layout().ty);
|
||||
}
|
||||
let imm = self.read_immediate_raw(op)?.right().unwrap();
|
||||
if matches!(*imm, Immediate::Uninit) {
|
||||
@ -669,7 +679,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
)?)?,
|
||||
op.layout,
|
||||
),
|
||||
"eval_place of a MIR place with type {:?} produced an interpreter operand with type {:?}",
|
||||
"eval_place of a MIR place with type {:?} produced an interpreter operand with type {}",
|
||||
mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty,
|
||||
op.layout.ty,
|
||||
);
|
||||
@ -692,7 +702,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
|
||||
Constant(constant) => {
|
||||
let c =
|
||||
self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal)?;
|
||||
self.subst_from_current_frame_and_normalize_erasing_regions(constant.const_)?;
|
||||
|
||||
// This can still fail:
|
||||
// * During ConstProp, with `TooGeneric` or since the `required_consts` were not all
|
||||
|
@ -1,7 +1,7 @@
|
||||
use rustc_apfloat::Float;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::mir::interpret::{InterpResult, Scalar};
|
||||
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::layout::TyAndLayout;
|
||||
use rustc_middle::ty::{self, FloatTy, Ty};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_target::abi::Abi;
|
||||
@ -20,9 +20,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
right: &ImmTy<'tcx, M::Provenance>,
|
||||
dest: &PlaceTy<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let (val, overflowed, ty) = self.overflowing_binary_op(op, &left, &right)?;
|
||||
let (val, overflowed) = self.overflowing_binary_op(op, &left, &right)?;
|
||||
debug_assert_eq!(
|
||||
Ty::new_tup(self.tcx.tcx, &[ty, self.tcx.types.bool]),
|
||||
Ty::new_tup(self.tcx.tcx, &[val.layout.ty, self.tcx.types.bool]),
|
||||
dest.layout.ty,
|
||||
"type mismatch for result of {op:?}",
|
||||
);
|
||||
@ -30,7 +30,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
if let Abi::ScalarPair(..) = dest.layout.abi {
|
||||
// We can use the optimized path and avoid `place_field` (which might do
|
||||
// `force_allocation`).
|
||||
let pair = Immediate::ScalarPair(val, Scalar::from_bool(overflowed));
|
||||
let pair = Immediate::ScalarPair(val.to_scalar(), Scalar::from_bool(overflowed));
|
||||
self.write_immediate(pair, dest)?;
|
||||
} else {
|
||||
assert!(self.tcx.sess.opts.unstable_opts.randomize_layout);
|
||||
@ -38,7 +38,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
// do a component-wise write here. This code path is slower than the above because
|
||||
// `place_field` will have to `force_allocate` locals here.
|
||||
let val_field = self.project_field(dest, 0)?;
|
||||
self.write_scalar(val, &val_field)?;
|
||||
self.write_scalar(val.to_scalar(), &val_field)?;
|
||||
let overflowed_field = self.project_field(dest, 1)?;
|
||||
self.write_scalar(Scalar::from_bool(overflowed), &overflowed_field)?;
|
||||
}
|
||||
@ -54,9 +54,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
right: &ImmTy<'tcx, M::Provenance>,
|
||||
dest: &PlaceTy<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx> {
|
||||
let (val, _overflowed, ty) = self.overflowing_binary_op(op, left, right)?;
|
||||
assert_eq!(ty, dest.layout.ty, "type mismatch for result of {op:?}");
|
||||
self.write_scalar(val, dest)
|
||||
let val = self.wrapping_binary_op(op, left, right)?;
|
||||
assert_eq!(val.layout.ty, dest.layout.ty, "type mismatch for result of {op:?}");
|
||||
self.write_immediate(*val, dest)
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
bin_op: mir::BinOp,
|
||||
l: char,
|
||||
r: char,
|
||||
) -> (Scalar<M::Provenance>, bool, Ty<'tcx>) {
|
||||
) -> (ImmTy<'tcx, M::Provenance>, bool) {
|
||||
use rustc_middle::mir::BinOp::*;
|
||||
|
||||
let res = match bin_op {
|
||||
@ -78,7 +78,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
Ge => l >= r,
|
||||
_ => span_bug!(self.cur_span(), "Invalid operation on char: {:?}", bin_op),
|
||||
};
|
||||
(Scalar::from_bool(res), false, self.tcx.types.bool)
|
||||
(ImmTy::from_bool(res, *self.tcx), false)
|
||||
}
|
||||
|
||||
fn binary_bool_op(
|
||||
@ -86,7 +86,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
bin_op: mir::BinOp,
|
||||
l: bool,
|
||||
r: bool,
|
||||
) -> (Scalar<M::Provenance>, bool, Ty<'tcx>) {
|
||||
) -> (ImmTy<'tcx, M::Provenance>, bool) {
|
||||
use rustc_middle::mir::BinOp::*;
|
||||
|
||||
let res = match bin_op {
|
||||
@ -101,33 +101,33 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
BitXor => l ^ r,
|
||||
_ => span_bug!(self.cur_span(), "Invalid operation on bool: {:?}", bin_op),
|
||||
};
|
||||
(Scalar::from_bool(res), false, self.tcx.types.bool)
|
||||
(ImmTy::from_bool(res, *self.tcx), false)
|
||||
}
|
||||
|
||||
fn binary_float_op<F: Float + Into<Scalar<M::Provenance>>>(
|
||||
&self,
|
||||
bin_op: mir::BinOp,
|
||||
ty: Ty<'tcx>,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
l: F,
|
||||
r: F,
|
||||
) -> (Scalar<M::Provenance>, bool, Ty<'tcx>) {
|
||||
) -> (ImmTy<'tcx, M::Provenance>, bool) {
|
||||
use rustc_middle::mir::BinOp::*;
|
||||
|
||||
let (val, ty) = match bin_op {
|
||||
Eq => (Scalar::from_bool(l == r), self.tcx.types.bool),
|
||||
Ne => (Scalar::from_bool(l != r), self.tcx.types.bool),
|
||||
Lt => (Scalar::from_bool(l < r), self.tcx.types.bool),
|
||||
Le => (Scalar::from_bool(l <= r), self.tcx.types.bool),
|
||||
Gt => (Scalar::from_bool(l > r), self.tcx.types.bool),
|
||||
Ge => (Scalar::from_bool(l >= r), self.tcx.types.bool),
|
||||
Add => ((l + r).value.into(), ty),
|
||||
Sub => ((l - r).value.into(), ty),
|
||||
Mul => ((l * r).value.into(), ty),
|
||||
Div => ((l / r).value.into(), ty),
|
||||
Rem => ((l % r).value.into(), ty),
|
||||
let val = match bin_op {
|
||||
Eq => ImmTy::from_bool(l == r, *self.tcx),
|
||||
Ne => ImmTy::from_bool(l != r, *self.tcx),
|
||||
Lt => ImmTy::from_bool(l < r, *self.tcx),
|
||||
Le => ImmTy::from_bool(l <= r, *self.tcx),
|
||||
Gt => ImmTy::from_bool(l > r, *self.tcx),
|
||||
Ge => ImmTy::from_bool(l >= r, *self.tcx),
|
||||
Add => ImmTy::from_scalar((l + r).value.into(), layout),
|
||||
Sub => ImmTy::from_scalar((l - r).value.into(), layout),
|
||||
Mul => ImmTy::from_scalar((l * r).value.into(), layout),
|
||||
Div => ImmTy::from_scalar((l / r).value.into(), layout),
|
||||
Rem => ImmTy::from_scalar((l % r).value.into(), layout),
|
||||
_ => span_bug!(self.cur_span(), "invalid float op: `{:?}`", bin_op),
|
||||
};
|
||||
(val, false, ty)
|
||||
(val, false)
|
||||
}
|
||||
|
||||
fn binary_int_op(
|
||||
@ -138,7 +138,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
left_layout: TyAndLayout<'tcx>,
|
||||
r: u128,
|
||||
right_layout: TyAndLayout<'tcx>,
|
||||
) -> InterpResult<'tcx, (Scalar<M::Provenance>, bool, Ty<'tcx>)> {
|
||||
) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> {
|
||||
use rustc_middle::mir::BinOp::*;
|
||||
|
||||
let throw_ub_on_overflow = match bin_op {
|
||||
@ -200,19 +200,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
);
|
||||
}
|
||||
|
||||
return Ok((Scalar::from_uint(truncated, left_layout.size), overflow, left_layout.ty));
|
||||
return Ok((ImmTy::from_uint(truncated, left_layout), overflow));
|
||||
}
|
||||
|
||||
// For the remaining ops, the types must be the same on both sides
|
||||
if left_layout.ty != right_layout.ty {
|
||||
span_bug!(
|
||||
self.cur_span(),
|
||||
"invalid asymmetric binary op {:?}: {:?} ({:?}), {:?} ({:?})",
|
||||
bin_op,
|
||||
l,
|
||||
left_layout.ty,
|
||||
r,
|
||||
right_layout.ty,
|
||||
"invalid asymmetric binary op {bin_op:?}: {l:?} ({l_ty}), {r:?} ({r_ty})",
|
||||
l_ty = left_layout.ty,
|
||||
r_ty = right_layout.ty,
|
||||
)
|
||||
}
|
||||
|
||||
@ -230,7 +227,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
if let Some(op) = op {
|
||||
let l = self.sign_extend(l, left_layout) as i128;
|
||||
let r = self.sign_extend(r, right_layout) as i128;
|
||||
return Ok((Scalar::from_bool(op(&l, &r)), false, self.tcx.types.bool));
|
||||
return Ok((ImmTy::from_bool(op(&l, &r), *self.tcx), false));
|
||||
}
|
||||
let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op {
|
||||
Div if r == 0 => throw_ub!(DivisionByZero),
|
||||
@ -267,22 +264,22 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
if overflow && let Some(intrinsic_name) = throw_ub_on_overflow {
|
||||
throw_ub_custom!(fluent::const_eval_overflow, name = intrinsic_name);
|
||||
}
|
||||
return Ok((Scalar::from_uint(truncated, size), overflow, left_layout.ty));
|
||||
return Ok((ImmTy::from_uint(truncated, left_layout), overflow));
|
||||
}
|
||||
}
|
||||
|
||||
let (val, ty) = match bin_op {
|
||||
Eq => (Scalar::from_bool(l == r), self.tcx.types.bool),
|
||||
Ne => (Scalar::from_bool(l != r), self.tcx.types.bool),
|
||||
let val = match bin_op {
|
||||
Eq => ImmTy::from_bool(l == r, *self.tcx),
|
||||
Ne => ImmTy::from_bool(l != r, *self.tcx),
|
||||
|
||||
Lt => (Scalar::from_bool(l < r), self.tcx.types.bool),
|
||||
Le => (Scalar::from_bool(l <= r), self.tcx.types.bool),
|
||||
Gt => (Scalar::from_bool(l > r), self.tcx.types.bool),
|
||||
Ge => (Scalar::from_bool(l >= r), self.tcx.types.bool),
|
||||
Lt => ImmTy::from_bool(l < r, *self.tcx),
|
||||
Le => ImmTy::from_bool(l <= r, *self.tcx),
|
||||
Gt => ImmTy::from_bool(l > r, *self.tcx),
|
||||
Ge => ImmTy::from_bool(l >= r, *self.tcx),
|
||||
|
||||
BitOr => (Scalar::from_uint(l | r, size), left_layout.ty),
|
||||
BitAnd => (Scalar::from_uint(l & r, size), left_layout.ty),
|
||||
BitXor => (Scalar::from_uint(l ^ r, size), left_layout.ty),
|
||||
BitOr => ImmTy::from_uint(l | r, left_layout),
|
||||
BitAnd => ImmTy::from_uint(l & r, left_layout),
|
||||
BitXor => ImmTy::from_uint(l ^ r, left_layout),
|
||||
|
||||
Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Rem | Div => {
|
||||
assert!(!left_layout.abi.is_signed());
|
||||
@ -304,12 +301,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
if overflow && let Some(intrinsic_name) = throw_ub_on_overflow {
|
||||
throw_ub_custom!(fluent::const_eval_overflow, name = intrinsic_name);
|
||||
}
|
||||
return Ok((Scalar::from_uint(truncated, size), overflow, left_layout.ty));
|
||||
return Ok((ImmTy::from_uint(truncated, left_layout), overflow));
|
||||
}
|
||||
|
||||
_ => span_bug!(
|
||||
self.cur_span(),
|
||||
"invalid binary op {:?}: {:?}, {:?} (both {:?})",
|
||||
"invalid binary op {:?}: {:?}, {:?} (both {})",
|
||||
bin_op,
|
||||
l,
|
||||
r,
|
||||
@ -317,7 +314,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
),
|
||||
};
|
||||
|
||||
Ok((val, false, ty))
|
||||
Ok((val, false))
|
||||
}
|
||||
|
||||
fn binary_ptr_op(
|
||||
@ -325,7 +322,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
bin_op: mir::BinOp,
|
||||
left: &ImmTy<'tcx, M::Provenance>,
|
||||
right: &ImmTy<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, (Scalar<M::Provenance>, bool, Ty<'tcx>)> {
|
||||
) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> {
|
||||
use rustc_middle::mir::BinOp::*;
|
||||
|
||||
match bin_op {
|
||||
@ -336,7 +333,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty;
|
||||
|
||||
let offset_ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset_count)?;
|
||||
Ok((Scalar::from_maybe_pointer(offset_ptr, self), false, left.layout.ty))
|
||||
Ok((
|
||||
ImmTy::from_scalar(Scalar::from_maybe_pointer(offset_ptr, self), left.layout),
|
||||
false,
|
||||
))
|
||||
}
|
||||
|
||||
// Fall back to machine hook so Miri can support more pointer ops.
|
||||
@ -344,16 +344,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the result of the specified operation, whether it overflowed, and
|
||||
/// the result type.
|
||||
/// Returns the result of the specified operation, and whether it overflowed.
|
||||
pub fn overflowing_binary_op(
|
||||
&self,
|
||||
bin_op: mir::BinOp,
|
||||
left: &ImmTy<'tcx, M::Provenance>,
|
||||
right: &ImmTy<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, (Scalar<M::Provenance>, bool, Ty<'tcx>)> {
|
||||
) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> {
|
||||
trace!(
|
||||
"Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
|
||||
"Running binary op {:?}: {:?} ({}), {:?} ({})",
|
||||
bin_op,
|
||||
*left,
|
||||
left.layout.ty,
|
||||
@ -376,15 +375,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
}
|
||||
ty::Float(fty) => {
|
||||
assert_eq!(left.layout.ty, right.layout.ty);
|
||||
let ty = left.layout.ty;
|
||||
let layout = left.layout;
|
||||
let left = left.to_scalar();
|
||||
let right = right.to_scalar();
|
||||
Ok(match fty {
|
||||
FloatTy::F32 => {
|
||||
self.binary_float_op(bin_op, ty, left.to_f32()?, right.to_f32()?)
|
||||
self.binary_float_op(bin_op, layout, left.to_f32()?, right.to_f32()?)
|
||||
}
|
||||
FloatTy::F64 => {
|
||||
self.binary_float_op(bin_op, ty, left.to_f64()?, right.to_f64()?)
|
||||
self.binary_float_op(bin_op, layout, left.to_f64()?, right.to_f64()?)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -392,7 +391,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
// the RHS type can be different, e.g. for shifts -- but it has to be integral, too
|
||||
assert!(
|
||||
right.layout.ty.is_integral(),
|
||||
"Unexpected types for BinOp: {:?} {:?} {:?}",
|
||||
"Unexpected types for BinOp: {} {:?} {}",
|
||||
left.layout.ty,
|
||||
bin_op,
|
||||
right.layout.ty
|
||||
@ -407,7 +406,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
// (Even when both sides are pointers, their type might differ, see issue #91636)
|
||||
assert!(
|
||||
right.layout.ty.is_any_ptr() || right.layout.ty.is_integral(),
|
||||
"Unexpected types for BinOp: {:?} {:?} {:?}",
|
||||
"Unexpected types for BinOp: {} {:?} {}",
|
||||
left.layout.ty,
|
||||
bin_op,
|
||||
right.layout.ty
|
||||
@ -417,22 +416,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
}
|
||||
_ => span_bug!(
|
||||
self.cur_span(),
|
||||
"Invalid MIR: bad LHS type for binop: {:?}",
|
||||
"Invalid MIR: bad LHS type for binop: {}",
|
||||
left.layout.ty
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Typed version of `overflowing_binary_op`, returning an `ImmTy`. Also ignores overflows.
|
||||
#[inline]
|
||||
pub fn binary_op(
|
||||
pub fn wrapping_binary_op(
|
||||
&self,
|
||||
bin_op: mir::BinOp,
|
||||
left: &ImmTy<'tcx, M::Provenance>,
|
||||
right: &ImmTy<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
|
||||
let (val, _overflow, ty) = self.overflowing_binary_op(bin_op, left, right)?;
|
||||
Ok(ImmTy::from_scalar(val, self.layout_of(ty)?))
|
||||
let (val, _overflow) = self.overflowing_binary_op(bin_op, left, right)?;
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
/// Returns the result of the specified operation, whether it overflowed, and
|
||||
@ -441,12 +439,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
&self,
|
||||
un_op: mir::UnOp,
|
||||
val: &ImmTy<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, (Scalar<M::Provenance>, bool, Ty<'tcx>)> {
|
||||
) -> InterpResult<'tcx, (ImmTy<'tcx, M::Provenance>, bool)> {
|
||||
use rustc_middle::mir::UnOp::*;
|
||||
|
||||
let layout = val.layout;
|
||||
let val = val.to_scalar();
|
||||
trace!("Running unary op {:?}: {:?} ({:?})", un_op, val, layout.ty);
|
||||
trace!("Running unary op {:?}: {:?} ({})", un_op, val, layout.ty);
|
||||
|
||||
match layout.ty.kind() {
|
||||
ty::Bool => {
|
||||
@ -455,7 +453,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
Not => !val,
|
||||
_ => span_bug!(self.cur_span(), "Invalid bool op {:?}", un_op),
|
||||
};
|
||||
Ok((Scalar::from_bool(res), false, self.tcx.types.bool))
|
||||
Ok((ImmTy::from_bool(res, *self.tcx), false))
|
||||
}
|
||||
ty::Float(fty) => {
|
||||
let res = match (un_op, fty) {
|
||||
@ -463,7 +461,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
(Neg, FloatTy::F64) => Scalar::from_f64(-val.to_f64()?),
|
||||
_ => span_bug!(self.cur_span(), "Invalid float op {:?}", un_op),
|
||||
};
|
||||
Ok((res, false, layout.ty))
|
||||
Ok((ImmTy::from_scalar(res, layout), false))
|
||||
}
|
||||
_ => {
|
||||
assert!(layout.ty.is_integral());
|
||||
@ -482,17 +480,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
(truncated, overflow || self.sign_extend(truncated, layout) != res)
|
||||
}
|
||||
};
|
||||
Ok((Scalar::from_uint(res, layout.size), overflow, layout.ty))
|
||||
Ok((ImmTy::from_uint(res, layout), overflow))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unary_op(
|
||||
#[inline]
|
||||
pub fn wrapping_unary_op(
|
||||
&self,
|
||||
un_op: mir::UnOp,
|
||||
val: &ImmTy<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
|
||||
let (val, _overflow, ty) = self.overflowing_unary_op(un_op, val)?;
|
||||
Ok(ImmTy::from_scalar(val, self.layout_of(ty)?))
|
||||
let (val, _overflow) = self.overflowing_unary_op(un_op, val)?;
|
||||
Ok(val)
|
||||
}
|
||||
}
|
||||
|
@ -460,7 +460,7 @@ where
|
||||
trace!("deref to {} on {:?}", val.layout.ty, *val);
|
||||
|
||||
if val.layout.ty.is_box() {
|
||||
bug!("dereferencing {:?}", val.layout.ty);
|
||||
bug!("dereferencing {}", val.layout.ty);
|
||||
}
|
||||
|
||||
let mplace = self.ref_to_mplace(&val)?;
|
||||
@ -582,7 +582,7 @@ where
|
||||
)?)?,
|
||||
place.layout,
|
||||
),
|
||||
"eval_place of a MIR place with type {:?} produced an interpreter place with type {:?}",
|
||||
"eval_place of a MIR place with type {:?} produced an interpreter place with type {}",
|
||||
mir_place.ty(&self.frame().body.local_decls, *self.tcx).ty,
|
||||
place.layout.ty,
|
||||
);
|
||||
@ -835,7 +835,7 @@ where
|
||||
if !allow_transmute && !layout_compat {
|
||||
span_bug!(
|
||||
self.cur_span(),
|
||||
"type mismatch when copying!\nsrc: {:?},\ndest: {:?}",
|
||||
"type mismatch when copying!\nsrc: {},\ndest: {}",
|
||||
src.layout().ty,
|
||||
dest.layout().ty,
|
||||
);
|
||||
|
@ -177,7 +177,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
UnaryOp(un_op, ref operand) => {
|
||||
// The operand always has the same type as the result.
|
||||
let val = self.read_immediate(&self.eval_operand(operand, Some(dest.layout))?)?;
|
||||
let val = self.unary_op(un_op, &val)?;
|
||||
let val = self.wrapping_unary_op(un_op, &val)?;
|
||||
assert_eq!(val.layout, dest.layout, "layout mismatch for result of {un_op:?}");
|
||||
self.write_immediate(*val, &dest)?;
|
||||
}
|
||||
|
@ -98,14 +98,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
for (const_int, target) in targets.iter() {
|
||||
// Compare using MIR BinOp::Eq, to also support pointer values.
|
||||
// (Avoiding `self.binary_op` as that does some redundant layout computation.)
|
||||
let res = self
|
||||
.overflowing_binary_op(
|
||||
mir::BinOp::Eq,
|
||||
&discr,
|
||||
&ImmTy::from_uint(const_int, discr.layout),
|
||||
)?
|
||||
.0;
|
||||
if res.to_bool()? {
|
||||
let res = self.wrapping_binary_op(
|
||||
mir::BinOp::Eq,
|
||||
&discr,
|
||||
&ImmTy::from_uint(const_int, discr.layout),
|
||||
)?;
|
||||
if res.to_scalar().to_bool()? {
|
||||
target_block = target;
|
||||
break;
|
||||
}
|
||||
@ -151,7 +149,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
}
|
||||
_ => span_bug!(
|
||||
terminator.source_info.span,
|
||||
"invalid callee of type {:?}",
|
||||
"invalid callee of type {}",
|
||||
func.layout.ty
|
||||
),
|
||||
};
|
||||
@ -681,10 +679,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
self.storage_live(local)?;
|
||||
// Must be a tuple
|
||||
let ty::Tuple(fields) = ty.kind() else {
|
||||
span_bug!(
|
||||
self.cur_span(),
|
||||
"non-tuple type for `spread_arg`: {ty:?}"
|
||||
)
|
||||
span_bug!(self.cur_span(), "non-tuple type for `spread_arg`: {ty}")
|
||||
};
|
||||
for (i, field_ty) in fields.iter().enumerate() {
|
||||
let dest = dest.project_deeper(
|
||||
@ -926,7 +921,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
target: mir::BasicBlock,
|
||||
unwind: mir::UnwindAction,
|
||||
) -> InterpResult<'tcx> {
|
||||
trace!("drop_in_place: {:?},\n {:?}, {:?}", *place, place.layout.ty, instance);
|
||||
trace!("drop_in_place: {:?},\n instance={:?}", place, instance);
|
||||
// We take the address of the object. This may well be unaligned, which is fine
|
||||
// for us here. However, unaligned accesses will probably make the actual drop
|
||||
// implementation fail -- a problem shared by rustc.
|
||||
|
@ -167,7 +167,7 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
|
||||
false
|
||||
}
|
||||
|
||||
hir::ConstContext::Const | hir::ConstContext::Static(_) => {
|
||||
hir::ConstContext::Const { .. } | hir::ConstContext::Static(_) => {
|
||||
let mut cursor = FlowSensitiveAnalysis::new(CustomEq, ccx)
|
||||
.into_engine(ccx.tcx, &ccx.body)
|
||||
.iterate_to_fixpoint()
|
||||
|
@ -346,8 +346,8 @@ where
|
||||
};
|
||||
|
||||
// Check the qualifs of the value of `const` items.
|
||||
let uneval = match constant.literal {
|
||||
ConstantKind::Ty(ct)
|
||||
let uneval = match constant.const_ {
|
||||
Const::Ty(ct)
|
||||
if matches!(
|
||||
ct.kind(),
|
||||
ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_)
|
||||
@ -355,11 +355,11 @@ where
|
||||
{
|
||||
None
|
||||
}
|
||||
ConstantKind::Ty(c) => {
|
||||
Const::Ty(c) => {
|
||||
bug!("expected ConstKind::Param or ConstKind::Value here, found {:?}", c)
|
||||
}
|
||||
ConstantKind::Unevaluated(uv, _) => Some(uv),
|
||||
ConstantKind::Val(..) => None,
|
||||
Const::Unevaluated(uv, _) => Some(uv),
|
||||
Const::Val(..) => None,
|
||||
};
|
||||
|
||||
if let Some(mir::UnevaluatedConst { def, args: _, promoted }) = uneval {
|
||||
@ -383,5 +383,5 @@ where
|
||||
}
|
||||
|
||||
// Otherwise use the qualifs of the type.
|
||||
Q::in_any_value_of_ty(cx, constant.literal.ty())
|
||||
Q::in_any_value_of_ty(cx, constant.const_.ty())
|
||||
}
|
||||
|
@ -372,7 +372,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||
StatementKind::Assign(box (
|
||||
_,
|
||||
Rvalue::Use(Operand::Constant(c)),
|
||||
)) => c.literal.try_eval_target_usize(self.tcx, self.param_env),
|
||||
)) => c.const_.try_eval_target_usize(self.tcx, self.param_env),
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
@ -554,7 +554,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||
// Integer division: the RHS must be a non-zero const.
|
||||
let const_val = match rhs {
|
||||
Operand::Constant(c) => {
|
||||
c.literal.try_eval_bits(self.tcx, self.param_env, lhs_ty)
|
||||
c.const_.try_eval_bits(self.tcx, self.param_env)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
@ -644,7 +644,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||
// Everywhere else, we require `#[rustc_promotable]` on the callee.
|
||||
let promote_all_const_fn = matches!(
|
||||
self.const_kind,
|
||||
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const)
|
||||
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { inline: false })
|
||||
);
|
||||
if !promote_all_const_fn {
|
||||
if let ty::FnDef(def_id, _) = *fn_ty.kind() {
|
||||
@ -766,10 +766,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||
if self.keep_original {
|
||||
rhs.clone()
|
||||
} else {
|
||||
let unit = Rvalue::Use(Operand::Constant(Box::new(Constant {
|
||||
let unit = Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
|
||||
span: statement.source_info.span,
|
||||
user_ty: None,
|
||||
literal: ConstantKind::zero_sized(self.tcx.types.unit),
|
||||
const_: Const::zero_sized(self.tcx.types.unit),
|
||||
})));
|
||||
mem::replace(rhs, unit)
|
||||
},
|
||||
@ -844,10 +844,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
||||
let args = tcx.erase_regions(GenericArgs::identity_for_item(tcx, def));
|
||||
let uneval = mir::UnevaluatedConst { def, args, promoted: Some(promoted_id) };
|
||||
|
||||
Operand::Constant(Box::new(Constant {
|
||||
Operand::Constant(Box::new(ConstOperand {
|
||||
span,
|
||||
user_ty: None,
|
||||
literal: ConstantKind::Unevaluated(uneval, ty),
|
||||
const_: Const::Unevaluated(uneval, ty),
|
||||
}))
|
||||
};
|
||||
|
||||
@ -1041,8 +1041,8 @@ pub fn is_const_fn_in_array_repeat_expression<'tcx>(
|
||||
if let Some(Terminator { kind: TerminatorKind::Call { func, destination, .. }, .. }) =
|
||||
&block.terminator
|
||||
{
|
||||
if let Operand::Constant(box Constant { literal, .. }) = func {
|
||||
if let ty::FnDef(def_id, _) = *literal.ty().kind() {
|
||||
if let Operand::Constant(box ConstOperand { const_, .. }) = func {
|
||||
if let ty::FnDef(def_id, _) = *const_.ty().kind() {
|
||||
if destination == place {
|
||||
if ccx.tcx.is_const_fn(def_id) {
|
||||
return true;
|
||||
|
@ -21,8 +21,16 @@ impl Lock {
|
||||
let lock_type = if exclusive { libc::F_WRLCK } else { libc::F_RDLCK };
|
||||
|
||||
let mut flock: libc::flock = unsafe { mem::zeroed() };
|
||||
flock.l_type = lock_type as libc::c_short;
|
||||
flock.l_whence = libc::SEEK_SET as libc::c_short;
|
||||
#[cfg(not(all(target_os = "hurd", target_arch = "x86")))]
|
||||
{
|
||||
flock.l_type = lock_type as libc::c_short;
|
||||
flock.l_whence = libc::SEEK_SET as libc::c_short;
|
||||
}
|
||||
#[cfg(all(target_os = "hurd", target_arch = "x86"))]
|
||||
{
|
||||
flock.l_type = lock_type as libc::c_int;
|
||||
flock.l_whence = libc::SEEK_SET as libc::c_int;
|
||||
}
|
||||
flock.l_start = 0;
|
||||
flock.l_len = 0;
|
||||
|
||||
@ -39,8 +47,16 @@ impl Lock {
|
||||
impl Drop for Lock {
|
||||
fn drop(&mut self) {
|
||||
let mut flock: libc::flock = unsafe { mem::zeroed() };
|
||||
flock.l_type = libc::F_UNLCK as libc::c_short;
|
||||
flock.l_whence = libc::SEEK_SET as libc::c_short;
|
||||
#[cfg(not(all(target_os = "hurd", target_arch = "x86")))]
|
||||
{
|
||||
flock.l_type = libc::F_UNLCK as libc::c_short;
|
||||
flock.l_whence = libc::SEEK_SET as libc::c_short;
|
||||
}
|
||||
#[cfg(all(target_os = "hurd", target_arch = "x86"))]
|
||||
{
|
||||
flock.l_type = libc::F_UNLCK as libc::c_int;
|
||||
flock.l_whence = libc::SEEK_SET as libc::c_int;
|
||||
}
|
||||
flock.l_start = 0;
|
||||
flock.l_len = 0;
|
||||
|
||||
|
@ -161,7 +161,7 @@ impl IntoDiagnosticArg for hir::ConstContext {
|
||||
DiagnosticArgValue::Str(Cow::Borrowed(match self {
|
||||
hir::ConstContext::ConstFn => "const_fn",
|
||||
hir::ConstContext::Static(_) => "static",
|
||||
hir::ConstContext::Const => "const",
|
||||
hir::ConstContext::Const { .. } => "const",
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
@ -1581,8 +1581,8 @@ pub enum BodyOwnerKind {
|
||||
/// Closures
|
||||
Closure,
|
||||
|
||||
/// Constants and associated constants.
|
||||
Const,
|
||||
/// Constants and associated constants, also including inline constants.
|
||||
Const { inline: bool },
|
||||
|
||||
/// Initializer of a `static` item.
|
||||
Static(Mutability),
|
||||
@ -1592,7 +1592,7 @@ impl BodyOwnerKind {
|
||||
pub fn is_fn_or_closure(self) -> bool {
|
||||
match self {
|
||||
BodyOwnerKind::Fn | BodyOwnerKind::Closure => true,
|
||||
BodyOwnerKind::Const | BodyOwnerKind::Static(_) => false,
|
||||
BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1615,7 +1615,7 @@ pub enum ConstContext {
|
||||
///
|
||||
/// For the most part, other contexts are treated just like a regular `const`, so they are
|
||||
/// lumped into the same category.
|
||||
Const,
|
||||
Const { inline: bool },
|
||||
}
|
||||
|
||||
impl ConstContext {
|
||||
@ -1624,7 +1624,7 @@ impl ConstContext {
|
||||
/// E.g. `const` or `static mut`.
|
||||
pub fn keyword_name(self) -> &'static str {
|
||||
match self {
|
||||
Self::Const => "const",
|
||||
Self::Const { .. } => "const",
|
||||
Self::Static(Mutability::Not) => "static",
|
||||
Self::Static(Mutability::Mut) => "static mut",
|
||||
Self::ConstFn => "const fn",
|
||||
@ -1637,7 +1637,7 @@ impl ConstContext {
|
||||
impl fmt::Display for ConstContext {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
Self::Const => write!(f, "constant"),
|
||||
Self::Const { .. } => write!(f, "constant"),
|
||||
Self::Static(_) => write!(f, "static"),
|
||||
Self::ConstFn => write!(f, "constant function"),
|
||||
}
|
||||
@ -2853,13 +2853,13 @@ impl ImplicitSelfKind {
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
|
||||
#[derive(HashStable_Generic)]
|
||||
pub enum IsAsync {
|
||||
Async,
|
||||
Async(Span),
|
||||
NotAsync,
|
||||
}
|
||||
|
||||
impl IsAsync {
|
||||
pub fn is_async(self) -> bool {
|
||||
self == IsAsync::Async
|
||||
matches!(self, IsAsync::Async(_))
|
||||
}
|
||||
}
|
||||
|
||||
@ -3296,7 +3296,7 @@ pub struct FnHeader {
|
||||
|
||||
impl FnHeader {
|
||||
pub fn is_async(&self) -> bool {
|
||||
matches!(&self.asyncness, IsAsync::Async)
|
||||
matches!(&self.asyncness, IsAsync::Async(_))
|
||||
}
|
||||
|
||||
pub fn is_const(&self) -> bool {
|
||||
@ -4091,10 +4091,10 @@ mod size_asserts {
|
||||
static_assert_size!(GenericBound<'_>, 48);
|
||||
static_assert_size!(Generics<'_>, 56);
|
||||
static_assert_size!(Impl<'_>, 80);
|
||||
static_assert_size!(ImplItem<'_>, 80);
|
||||
static_assert_size!(ImplItemKind<'_>, 32);
|
||||
static_assert_size!(Item<'_>, 80);
|
||||
static_assert_size!(ItemKind<'_>, 48);
|
||||
static_assert_size!(ImplItem<'_>, 88);
|
||||
static_assert_size!(ImplItemKind<'_>, 40);
|
||||
static_assert_size!(Item<'_>, 88);
|
||||
static_assert_size!(ItemKind<'_>, 56);
|
||||
static_assert_size!(Local<'_>, 64);
|
||||
static_assert_size!(Param<'_>, 32);
|
||||
static_assert_size!(Pat<'_>, 72);
|
||||
@ -4105,8 +4105,8 @@ mod size_asserts {
|
||||
static_assert_size!(Res, 12);
|
||||
static_assert_size!(Stmt<'_>, 32);
|
||||
static_assert_size!(StmtKind<'_>, 16);
|
||||
static_assert_size!(TraitItem<'_>, 80);
|
||||
static_assert_size!(TraitItemKind<'_>, 40);
|
||||
static_assert_size!(TraitItem<'_>, 88);
|
||||
static_assert_size!(TraitItemKind<'_>, 48);
|
||||
static_assert_size!(Ty<'_>, 48);
|
||||
static_assert_size!(TyKind<'_>, 32);
|
||||
// tidy-alphabetical-end
|
||||
|
@ -595,7 +595,7 @@ fn compare_asyncness<'tcx>(
|
||||
trait_m: ty::AssocItem,
|
||||
delay: bool,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
if tcx.asyncness(trait_m.def_id) == hir::IsAsync::Async {
|
||||
if tcx.asyncness(trait_m.def_id).is_async() {
|
||||
match tcx.fn_sig(impl_m.def_id).skip_binder().skip_binder().output().kind() {
|
||||
ty::Alias(ty::Opaque, ..) => {
|
||||
// allow both `async fn foo()` and `fn foo() -> impl Future`
|
||||
|
@ -11,8 +11,8 @@ use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
|
||||
|
||||
use std::ops::Not;
|
||||
|
||||
use super::check_function_signature;
|
||||
use crate::errors;
|
||||
use crate::require_same_types;
|
||||
|
||||
pub(crate) fn check_for_entry_fn(tcx: TyCtxt<'_>) {
|
||||
match tcx.entry_fn(()) {
|
||||
@ -112,7 +112,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
|
||||
}
|
||||
|
||||
let main_asyncness = tcx.asyncness(main_def_id);
|
||||
if let hir::IsAsync::Async = main_asyncness {
|
||||
if main_asyncness.is_async() {
|
||||
let asyncness_span = main_fn_asyncness_span(tcx, main_def_id);
|
||||
tcx.sess.emit_err(errors::MainFunctionAsync { span: main_span, asyncness: asyncness_span });
|
||||
error = true;
|
||||
@ -162,33 +162,33 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
|
||||
error = true;
|
||||
}
|
||||
// now we can take the return type of the given main function
|
||||
expected_return_type = main_fnsig.output();
|
||||
expected_return_type = norm_return_ty;
|
||||
} else {
|
||||
// standard () main return type
|
||||
expected_return_type = ty::Binder::dummy(Ty::new_unit(tcx));
|
||||
expected_return_type = tcx.types.unit;
|
||||
}
|
||||
|
||||
if error {
|
||||
return;
|
||||
}
|
||||
|
||||
let se_ty = Ty::new_fn_ptr(
|
||||
tcx,
|
||||
expected_return_type.map_bound(|expected_return_type| {
|
||||
tcx.mk_fn_sig([], expected_return_type, false, hir::Unsafety::Normal, Abi::Rust)
|
||||
}),
|
||||
);
|
||||
let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig(
|
||||
[],
|
||||
expected_return_type,
|
||||
false,
|
||||
hir::Unsafety::Normal,
|
||||
Abi::Rust,
|
||||
));
|
||||
|
||||
require_same_types(
|
||||
check_function_signature(
|
||||
tcx,
|
||||
&ObligationCause::new(
|
||||
ObligationCause::new(
|
||||
main_span,
|
||||
main_diagnostics_def_id,
|
||||
ObligationCauseCode::MainFunctionType,
|
||||
),
|
||||
param_env,
|
||||
se_ty,
|
||||
Ty::new_fn_ptr(tcx, main_fnsig),
|
||||
main_def_id,
|
||||
expected_sig,
|
||||
);
|
||||
}
|
||||
|
||||
@ -212,7 +212,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
|
||||
});
|
||||
error = true;
|
||||
}
|
||||
if let hir::IsAsync::Async = sig.header.asyncness {
|
||||
if sig.header.asyncness.is_async() {
|
||||
let span = tcx.def_span(it.owner_id);
|
||||
tcx.sess.emit_err(errors::StartAsync { span: span });
|
||||
error = true;
|
||||
@ -247,27 +247,23 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
|
||||
}
|
||||
}
|
||||
|
||||
let se_ty = Ty::new_fn_ptr(
|
||||
tcx,
|
||||
ty::Binder::dummy(tcx.mk_fn_sig(
|
||||
[tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))],
|
||||
tcx.types.isize,
|
||||
false,
|
||||
hir::Unsafety::Normal,
|
||||
Abi::Rust,
|
||||
)),
|
||||
);
|
||||
let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig(
|
||||
[tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))],
|
||||
tcx.types.isize,
|
||||
false,
|
||||
hir::Unsafety::Normal,
|
||||
Abi::Rust,
|
||||
));
|
||||
|
||||
require_same_types(
|
||||
check_function_signature(
|
||||
tcx,
|
||||
&ObligationCause::new(
|
||||
ObligationCause::new(
|
||||
start_span,
|
||||
start_def_id,
|
||||
ObligationCauseCode::StartFunctionType,
|
||||
),
|
||||
ty::ParamEnv::empty(), // start should not have any where bounds.
|
||||
se_ty,
|
||||
Ty::new_fn_ptr(tcx, tcx.fn_sig(start_def_id).instantiate_identity()),
|
||||
start_def_id.into(),
|
||||
expected_sig,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
|
@ -1,11 +1,11 @@
|
||||
//! Type-checking for the rust-intrinsic and platform-intrinsic
|
||||
//! intrinsics that the compiler exposes.
|
||||
|
||||
use crate::check::check_function_signature;
|
||||
use crate::errors::{
|
||||
UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction,
|
||||
WrongNumberOfGenericArgumentsToIntrinsic,
|
||||
};
|
||||
use crate::require_same_types;
|
||||
|
||||
use hir::def_id::DefId;
|
||||
use rustc_errors::{struct_span_err, DiagnosticMessage};
|
||||
@ -53,15 +53,12 @@ fn equate_intrinsic_type<'tcx>(
|
||||
&& gen_count_ok(own_counts.types, n_tps, "type")
|
||||
&& gen_count_ok(own_counts.consts, 0, "const")
|
||||
{
|
||||
let fty = Ty::new_fn_ptr(tcx, sig);
|
||||
let it_def_id = it.owner_id.def_id;
|
||||
let cause = ObligationCause::new(it.span, it_def_id, ObligationCauseCode::IntrinsicType);
|
||||
require_same_types(
|
||||
check_function_signature(
|
||||
tcx,
|
||||
&cause,
|
||||
ty::ParamEnv::empty(), // FIXME: do all intrinsics have an empty param env?
|
||||
Ty::new_fn_ptr(tcx, tcx.fn_sig(it.owner_id).instantiate_identity()),
|
||||
fty,
|
||||
ObligationCause::new(it.span, it_def_id, ObligationCauseCode::IntrinsicType),
|
||||
it_def_id.into(),
|
||||
sig,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -73,23 +73,31 @@ pub mod wfcheck;
|
||||
|
||||
pub use check::check_abi;
|
||||
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use check::check_mod_item_types;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_errors::{pluralize, struct_span_err, Diagnostic, DiagnosticBuilder};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_infer::infer::error_reporting::ObligationCauseExt as _;
|
||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_infer::infer::{self, TyCtxtInferExt as _};
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::{GenericArgs, GenericArgsRef};
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::source_map::DUMMY_SP;
|
||||
use rustc_span::symbol::{kw, Ident};
|
||||
use rustc_span::{self, BytePos, Span, Symbol};
|
||||
use rustc_span::{self, def_id::CRATE_DEF_ID, BytePos, Span, Symbol};
|
||||
use rustc_target::abi::VariantIdx;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
|
||||
use std::num::NonZeroU32;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
|
||||
use rustc_trait_selection::traits::ObligationCtxt;
|
||||
|
||||
use crate::errors;
|
||||
use crate::require_c_abi_if_c_variadic;
|
||||
@ -546,3 +554,79 @@ fn bad_non_zero_sized_fields<'tcx>(
|
||||
pub fn potentially_plural_count(count: usize, word: &str) -> String {
|
||||
format!("{} {}{}", count, word, pluralize!(count))
|
||||
}
|
||||
|
||||
pub fn check_function_signature<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mut cause: ObligationCause<'tcx>,
|
||||
fn_id: DefId,
|
||||
expected_sig: ty::PolyFnSig<'tcx>,
|
||||
) {
|
||||
let local_id = fn_id.as_local().unwrap_or(CRATE_DEF_ID);
|
||||
|
||||
let param_env = ty::ParamEnv::empty();
|
||||
|
||||
let infcx = &tcx.infer_ctxt().build();
|
||||
let ocx = ObligationCtxt::new(infcx);
|
||||
|
||||
let actual_sig = tcx.fn_sig(fn_id).instantiate_identity();
|
||||
|
||||
let norm_cause = ObligationCause::misc(cause.span, local_id);
|
||||
let actual_sig = ocx.normalize(&norm_cause, param_env, actual_sig);
|
||||
|
||||
let expected_ty = Ty::new_fn_ptr(tcx, expected_sig);
|
||||
let actual_ty = Ty::new_fn_ptr(tcx, actual_sig);
|
||||
|
||||
match ocx.eq(&cause, param_env, expected_ty, actual_ty) {
|
||||
Ok(()) => {
|
||||
let errors = ocx.select_all_or_error();
|
||||
if !errors.is_empty() {
|
||||
infcx.err_ctxt().report_fulfillment_errors(&errors);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
let err_ctxt = infcx.err_ctxt();
|
||||
if fn_id.is_local() {
|
||||
cause.span = extract_span_for_error_reporting(tcx, err, &cause, local_id);
|
||||
}
|
||||
let failure_code = cause.as_failure_code_diag(err, cause.span, vec![]);
|
||||
let mut diag = tcx.sess.create_err(failure_code);
|
||||
err_ctxt.note_type_err(
|
||||
&mut diag,
|
||||
&cause,
|
||||
None,
|
||||
Some(infer::ValuePairs::Sigs(ExpectedFound {
|
||||
expected: tcx.liberate_late_bound_regions(fn_id, expected_sig),
|
||||
found: tcx.liberate_late_bound_regions(fn_id, actual_sig),
|
||||
})),
|
||||
err,
|
||||
false,
|
||||
false,
|
||||
);
|
||||
diag.emit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||
let _ = ocx.resolve_regions_and_report_errors(local_id, &outlives_env);
|
||||
|
||||
fn extract_span_for_error_reporting<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
err: TypeError<'_>,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
fn_id: LocalDefId,
|
||||
) -> rustc_span::Span {
|
||||
let mut args = {
|
||||
let node = tcx.hir().expect_owner(fn_id);
|
||||
let decl = node.fn_decl().unwrap_or_else(|| bug!("expected fn decl, found {:?}", node));
|
||||
decl.inputs.iter().map(|t| t.span).chain(std::iter::once(decl.output.span()))
|
||||
};
|
||||
|
||||
match err {
|
||||
TypeError::ArgumentMutability(i)
|
||||
| TypeError::ArgumentSorts(ExpectedFound { .. }, i) => args.nth(i).unwrap(),
|
||||
_ => cause.span(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1213,7 +1213,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
||||
&& let Some(generics) = self.tcx.hir().get_generics(self.tcx.local_parent(param_id))
|
||||
&& let Some(param) = generics.params.iter().find(|p| p.def_id == param_id)
|
||||
&& param.is_elided_lifetime()
|
||||
&& let hir::IsAsync::NotAsync = self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id)
|
||||
&& !self.tcx.asyncness(lifetime_ref.hir_id.owner.def_id).is_async()
|
||||
&& !self.tcx.features().anonymous_lifetime_in_impl_trait
|
||||
{
|
||||
let mut diag = rustc_session::parse::feature_err(
|
||||
|
@ -99,7 +99,6 @@ use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
|
||||
use rustc_fluent_macro::fluent_messages;
|
||||
use rustc_hir as hir;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_middle::middle;
|
||||
use rustc_middle::query::Providers;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
@ -107,8 +106,7 @@ use rustc_middle::util;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::{symbol::sym, Span, DUMMY_SP};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCtxt};
|
||||
use rustc_trait_selection::traits;
|
||||
|
||||
use astconv::{AstConv, OnlySelfBounds};
|
||||
use bounds::Bounds;
|
||||
@ -151,28 +149,6 @@ fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi
|
||||
tcx.sess.emit_err(errors::VariadicFunctionCompatibleConvention { span, conventions });
|
||||
}
|
||||
|
||||
fn require_same_types<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
expected: Ty<'tcx>,
|
||||
actual: Ty<'tcx>,
|
||||
) {
|
||||
let infcx = &tcx.infer_ctxt().build();
|
||||
let ocx = ObligationCtxt::new(infcx);
|
||||
match ocx.eq(cause, param_env, expected, actual) {
|
||||
Ok(()) => {
|
||||
let errors = ocx.select_all_or_error();
|
||||
if !errors.is_empty() {
|
||||
infcx.err_ctxt().report_fulfillment_errors(&errors);
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
infcx.err_ctxt().report_mismatched_types(cause, expected, actual, err).emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
collect::provide(providers);
|
||||
coherence::provide(providers);
|
||||
|
@ -2304,7 +2304,7 @@ impl<'a> State<'a> {
|
||||
|
||||
match header.asyncness {
|
||||
hir::IsAsync::NotAsync => {}
|
||||
hir::IsAsync::Async => self.word_nbsp("async"),
|
||||
hir::IsAsync::Async(_) => self.word_nbsp("async"),
|
||||
}
|
||||
|
||||
self.print_unsafety(header.unsafety);
|
||||
|
@ -83,16 +83,6 @@ hir_typeck_int_to_fat_label_nightly = consider casting this expression to `*cons
|
||||
|
||||
hir_typeck_invalid_callee = expected function, found {$ty}
|
||||
|
||||
hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
|
||||
hir_typeck_lang_start_incorrect_number_params = incorrect number of parameters for the `start` lang item
|
||||
hir_typeck_lang_start_incorrect_number_params_note_expected_count = the `start` lang item should have four parameters, but found {$found_param_count}
|
||||
|
||||
hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` lang item is incorrect
|
||||
.suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
|
||||
|
||||
hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect
|
||||
.suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
|
||||
|
||||
hir_typeck_lossy_provenance_int2ptr =
|
||||
strict provenance disallows casting integer `{$expr_ty}` to pointer `{$cast_ty}`
|
||||
.suggestion = use `.with_addr()` to adjust a valid pointer in the same allocation, to this address
|
||||
|
@ -788,7 +788,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
|
||||
let effect = match const_context {
|
||||
_ if host_always_on => tcx.consts.true_,
|
||||
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => tcx.consts.false_,
|
||||
Some(hir::ConstContext::Static(_) | hir::ConstContext::Const { .. }) => {
|
||||
tcx.consts.false_
|
||||
}
|
||||
Some(hir::ConstContext::ConstFn) => {
|
||||
let args = ty::GenericArgs::identity_for_item(tcx, context);
|
||||
args.host_effect_param().expect("ConstContext::Maybe must have host effect param")
|
||||
|
@ -1,7 +1,6 @@
|
||||
use std::cell::RefCell;
|
||||
|
||||
use crate::coercion::CoerceMany;
|
||||
use crate::errors::{
|
||||
LangStartIncorrectNumberArgs, LangStartIncorrectParam, LangStartIncorrectRetTy,
|
||||
};
|
||||
use crate::gather_locals::GatherLocalsVisitor;
|
||||
use crate::FnCtxt;
|
||||
use crate::GeneratorTypes;
|
||||
@ -9,14 +8,15 @@ use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::lang_items::LangItem;
|
||||
use rustc_hir_analysis::check::fn_maybe_err;
|
||||
use rustc_hir_analysis::check::{check_function_signature, fn_maybe_err};
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::RegionVariableOrigin;
|
||||
use rustc_middle::ty::{self, Binder, Ty, TyCtxt};
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::traits;
|
||||
use std::cell::RefCell;
|
||||
use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
|
||||
|
||||
/// Helper used for fns and closures. Does the grungy work of checking a function
|
||||
/// body and returns the function context used for that purpose, since in the case of a fn item
|
||||
@ -166,52 +166,17 @@ pub(super) fn check_fn<'a, 'tcx>(
|
||||
if let Some(panic_impl_did) = tcx.lang_items().panic_impl()
|
||||
&& panic_impl_did == fn_def_id.to_def_id()
|
||||
{
|
||||
check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
|
||||
check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig);
|
||||
}
|
||||
|
||||
if let Some(lang_start_defid) = tcx.lang_items().start_fn() && lang_start_defid == fn_def_id.to_def_id() {
|
||||
check_lang_start_fn(tcx, fn_sig, decl, fn_def_id);
|
||||
check_lang_start_fn(tcx, fn_sig, fn_def_id);
|
||||
}
|
||||
|
||||
gen_ty
|
||||
}
|
||||
|
||||
fn check_panic_info_fn(
|
||||
tcx: TyCtxt<'_>,
|
||||
fn_id: LocalDefId,
|
||||
fn_sig: ty::FnSig<'_>,
|
||||
decl: &hir::FnDecl<'_>,
|
||||
declared_ret_ty: Ty<'_>,
|
||||
) {
|
||||
let Some(panic_info_did) = tcx.lang_items().panic_info() else {
|
||||
tcx.sess.err("language item required, but not found: `panic_info`");
|
||||
return;
|
||||
};
|
||||
|
||||
if *declared_ret_ty.kind() != ty::Never {
|
||||
tcx.sess.span_err(decl.output.span(), "return type should be `!`");
|
||||
}
|
||||
|
||||
let inputs = fn_sig.inputs();
|
||||
if inputs.len() != 1 {
|
||||
tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
|
||||
return;
|
||||
}
|
||||
|
||||
let arg_is_panic_info = match *inputs[0].kind() {
|
||||
ty::Ref(region, ty, mutbl) => match *ty.kind() {
|
||||
ty::Adt(ref adt, _) => {
|
||||
adt.did() == panic_info_did && mutbl.is_not() && !region.is_static()
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if !arg_is_panic_info {
|
||||
tcx.sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`");
|
||||
}
|
||||
|
||||
fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_>) {
|
||||
let DefKind::Fn = tcx.def_kind(fn_id) else {
|
||||
let span = tcx.def_span(fn_id);
|
||||
tcx.sess.span_err(span, "should be a function");
|
||||
@ -227,125 +192,87 @@ fn check_panic_info_fn(
|
||||
let span = tcx.def_span(fn_id);
|
||||
tcx.sess.span_err(span, "should have no const parameters");
|
||||
}
|
||||
|
||||
let Some(panic_info_did) = tcx.lang_items().panic_info() else {
|
||||
tcx.sess.err("language item required, but not found: `panic_info`");
|
||||
return;
|
||||
};
|
||||
|
||||
// build type `for<'a, 'b> fn(&'a PanicInfo<'b>) -> !`
|
||||
let panic_info_ty = tcx.type_of(panic_info_did).instantiate(
|
||||
tcx,
|
||||
&[ty::GenericArg::from(ty::Region::new_late_bound(
|
||||
tcx,
|
||||
ty::INNERMOST,
|
||||
ty::BoundRegion { var: ty::BoundVar::from_u32(1), kind: ty::BrAnon(None) },
|
||||
))],
|
||||
);
|
||||
let panic_info_ref_ty = Ty::new_imm_ref(
|
||||
tcx,
|
||||
ty::Region::new_late_bound(
|
||||
tcx,
|
||||
ty::INNERMOST,
|
||||
ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(None) },
|
||||
),
|
||||
panic_info_ty,
|
||||
);
|
||||
|
||||
let bounds = tcx.mk_bound_variable_kinds(&[
|
||||
ty::BoundVariableKind::Region(ty::BrAnon(None)),
|
||||
ty::BoundVariableKind::Region(ty::BrAnon(None)),
|
||||
]);
|
||||
let expected_sig = ty::Binder::bind_with_vars(
|
||||
tcx.mk_fn_sig([panic_info_ref_ty], tcx.types.never, false, fn_sig.unsafety, Abi::Rust),
|
||||
bounds,
|
||||
);
|
||||
|
||||
check_function_signature(
|
||||
tcx,
|
||||
ObligationCause::new(
|
||||
tcx.def_span(fn_id),
|
||||
fn_id,
|
||||
ObligationCauseCode::LangFunctionType(sym::panic_impl),
|
||||
),
|
||||
fn_id.into(),
|
||||
expected_sig,
|
||||
);
|
||||
}
|
||||
|
||||
fn check_lang_start_fn<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
fn_sig: ty::FnSig<'tcx>,
|
||||
decl: &'tcx hir::FnDecl<'tcx>,
|
||||
def_id: LocalDefId,
|
||||
) {
|
||||
let inputs = fn_sig.inputs();
|
||||
fn check_lang_start_fn<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: ty::FnSig<'tcx>, def_id: LocalDefId) {
|
||||
// build type `fn(main: fn() -> T, argc: isize, argv: *const *const u8, sigpipe: u8)`
|
||||
|
||||
let arg_count = inputs.len();
|
||||
if arg_count != 4 {
|
||||
tcx.sess.emit_err(LangStartIncorrectNumberArgs {
|
||||
params_span: tcx.def_span(def_id),
|
||||
found_param_count: arg_count,
|
||||
});
|
||||
}
|
||||
// make a Ty for the generic on the fn for diagnostics
|
||||
// FIXME: make the lang item generic checks check for the right generic *kind*
|
||||
// for example `start`'s generic should be a type parameter
|
||||
let generics = tcx.generics_of(def_id);
|
||||
let fn_generic = generics.param_at(0, tcx);
|
||||
let generic_ty = Ty::new_param(tcx, fn_generic.index, fn_generic.name);
|
||||
let main_fn_ty = Ty::new_fn_ptr(
|
||||
tcx,
|
||||
Binder::dummy(tcx.mk_fn_sig([], generic_ty, false, hir::Unsafety::Normal, Abi::Rust)),
|
||||
);
|
||||
|
||||
// only check args if they should exist by checking the count
|
||||
// note: this does not handle args being shifted or their order swapped very nicely
|
||||
// but it's a lang item, users shouldn't frequently encounter this
|
||||
let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig(
|
||||
[
|
||||
main_fn_ty,
|
||||
tcx.types.isize,
|
||||
Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8)),
|
||||
tcx.types.u8,
|
||||
],
|
||||
tcx.types.isize,
|
||||
false,
|
||||
fn_sig.unsafety,
|
||||
Abi::Rust,
|
||||
));
|
||||
|
||||
// first arg is `main: fn() -> T`
|
||||
if let Some(&main_arg) = inputs.get(0) {
|
||||
// make a Ty for the generic on the fn for diagnostics
|
||||
// FIXME: make the lang item generic checks check for the right generic *kind*
|
||||
// for example `start`'s generic should be a type parameter
|
||||
let generics = tcx.generics_of(def_id);
|
||||
let fn_generic = generics.param_at(0, tcx);
|
||||
let generic_ty = Ty::new_param(tcx, fn_generic.index, fn_generic.name);
|
||||
let expected_fn_sig =
|
||||
tcx.mk_fn_sig([], generic_ty, false, hir::Unsafety::Normal, Abi::Rust);
|
||||
let expected_ty = Ty::new_fn_ptr(tcx, Binder::dummy(expected_fn_sig));
|
||||
|
||||
// we emit the same error to suggest changing the arg no matter what's wrong with the arg
|
||||
let emit_main_fn_arg_err = || {
|
||||
tcx.sess.emit_err(LangStartIncorrectParam {
|
||||
param_span: decl.inputs[0].span,
|
||||
param_num: 1,
|
||||
expected_ty: expected_ty,
|
||||
found_ty: main_arg,
|
||||
});
|
||||
};
|
||||
|
||||
if let ty::FnPtr(main_fn_sig) = main_arg.kind() {
|
||||
let main_fn_inputs = main_fn_sig.inputs();
|
||||
if main_fn_inputs.iter().count() != 0 {
|
||||
emit_main_fn_arg_err();
|
||||
}
|
||||
|
||||
let output = main_fn_sig.output();
|
||||
output.map_bound(|ret_ty| {
|
||||
// if the output ty is a generic, it's probably the right one
|
||||
if !matches!(ret_ty.kind(), ty::Param(_)) {
|
||||
emit_main_fn_arg_err();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
emit_main_fn_arg_err();
|
||||
}
|
||||
}
|
||||
|
||||
// second arg is isize
|
||||
if let Some(&argc_arg) = inputs.get(1) {
|
||||
if argc_arg != tcx.types.isize {
|
||||
tcx.sess.emit_err(LangStartIncorrectParam {
|
||||
param_span: decl.inputs[1].span,
|
||||
param_num: 2,
|
||||
expected_ty: tcx.types.isize,
|
||||
found_ty: argc_arg,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// third arg is `*const *const u8`
|
||||
if let Some(&argv_arg) = inputs.get(2) {
|
||||
let mut argv_is_okay = false;
|
||||
if let ty::RawPtr(outer_ptr) = argv_arg.kind() {
|
||||
if outer_ptr.mutbl.is_not() {
|
||||
if let ty::RawPtr(inner_ptr) = outer_ptr.ty.kind() {
|
||||
if inner_ptr.mutbl.is_not() && inner_ptr.ty == tcx.types.u8 {
|
||||
argv_is_okay = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !argv_is_okay {
|
||||
let inner_ptr_ty =
|
||||
Ty::new_ptr(tcx, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: tcx.types.u8 });
|
||||
let expected_ty =
|
||||
Ty::new_ptr(tcx, ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: inner_ptr_ty });
|
||||
tcx.sess.emit_err(LangStartIncorrectParam {
|
||||
param_span: decl.inputs[2].span,
|
||||
param_num: 3,
|
||||
expected_ty,
|
||||
found_ty: argv_arg,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// fourth arg is `sigpipe: u8`
|
||||
if let Some(&sigpipe_arg) = inputs.get(3) {
|
||||
if sigpipe_arg != tcx.types.u8 {
|
||||
tcx.sess.emit_err(LangStartIncorrectParam {
|
||||
param_span: decl.inputs[3].span,
|
||||
param_num: 4,
|
||||
expected_ty: tcx.types.u8,
|
||||
found_ty: sigpipe_arg,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// output type is isize
|
||||
if fn_sig.output() != tcx.types.isize {
|
||||
tcx.sess.emit_err(LangStartIncorrectRetTy {
|
||||
ret_span: decl.output.span(),
|
||||
expected_ty: tcx.types.isize,
|
||||
found_ty: fn_sig.output(),
|
||||
});
|
||||
}
|
||||
check_function_signature(
|
||||
tcx,
|
||||
ObligationCause::new(
|
||||
tcx.def_span(def_id),
|
||||
def_id,
|
||||
ObligationCauseCode::LangFunctionType(sym::start),
|
||||
),
|
||||
def_id.into(),
|
||||
expected_sig,
|
||||
);
|
||||
}
|
||||
|
@ -236,39 +236,6 @@ impl AddToDiagnostic for TypeMismatchFruTypo {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_lang_start_incorrect_number_params)]
|
||||
#[note(hir_typeck_lang_start_incorrect_number_params_note_expected_count)]
|
||||
#[note(hir_typeck_lang_start_expected_sig_note)]
|
||||
pub struct LangStartIncorrectNumberArgs {
|
||||
#[primary_span]
|
||||
pub params_span: Span,
|
||||
pub found_param_count: usize,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_lang_start_incorrect_param)]
|
||||
pub struct LangStartIncorrectParam<'tcx> {
|
||||
#[primary_span]
|
||||
#[suggestion(style = "short", code = "{expected_ty}", applicability = "machine-applicable")]
|
||||
pub param_span: Span,
|
||||
|
||||
pub param_num: usize,
|
||||
pub expected_ty: Ty<'tcx>,
|
||||
pub found_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_lang_start_incorrect_ret_ty)]
|
||||
pub struct LangStartIncorrectRetTy<'tcx> {
|
||||
#[primary_span]
|
||||
#[suggestion(style = "short", code = "{expected_ty}", applicability = "machine-applicable")]
|
||||
pub ret_span: Span,
|
||||
|
||||
pub expected_ty: Ty<'tcx>,
|
||||
pub found_ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(LintDiagnostic)]
|
||||
#[diag(hir_typeck_lossy_provenance_int2ptr)]
|
||||
#[help]
|
||||
|
@ -987,10 +987,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let bound_vars = self.tcx.late_bound_vars(fn_id);
|
||||
let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars));
|
||||
let ty = match self.tcx.asyncness(fn_id.owner) {
|
||||
hir::IsAsync::Async => self.get_impl_future_output_ty(ty).unwrap_or_else(|| {
|
||||
ty::Asyncness::Yes => self.get_impl_future_output_ty(ty).unwrap_or_else(|| {
|
||||
span_bug!(fn_decl.output.span(), "failed to get output type of async function")
|
||||
}),
|
||||
hir::IsAsync::NotAsync => ty,
|
||||
ty::Asyncness::No => ty,
|
||||
};
|
||||
let ty = self.normalize(expr.span, ty);
|
||||
if self.can_coerce(found, ty) {
|
||||
|
@ -46,7 +46,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
// Type only exists for constants and statics, not functions.
|
||||
match self.tcx.hir().body_owner_kind(item_def_id) {
|
||||
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => {
|
||||
hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) => {
|
||||
let item_hir_id = self.tcx.hir().local_def_id_to_hir_id(item_def_id);
|
||||
wbcx.visit_node_id(body.value.span, item_hir_id);
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
|
||||
use rustc_hir::intravisit::{self, Visitor};
|
||||
use rustc_middle::dep_graph::{
|
||||
DepGraphQuery, DepKind, DepNode, DepNodeExt, DepNodeFilter, EdgeFilter,
|
||||
dep_kinds, DepGraphQuery, DepKind, DepNode, DepNodeExt, DepNodeFilter, EdgeFilter,
|
||||
};
|
||||
use rustc_middle::hir::nested_filter;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
@ -129,7 +129,7 @@ impl<'tcx> IfThisChanged<'tcx> {
|
||||
let dep_node_interned = self.argument(attr);
|
||||
let dep_node = match dep_node_interned {
|
||||
None => {
|
||||
DepNode::from_def_path_hash(self.tcx, def_path_hash, DepKind::hir_owner)
|
||||
DepNode::from_def_path_hash(self.tcx, def_path_hash, dep_kinds::hir_owner)
|
||||
}
|
||||
Some(n) => {
|
||||
match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) {
|
||||
|
@ -3,7 +3,7 @@
|
||||
use crate::errors;
|
||||
use rustc_data_structures::memmap::Mmap;
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
use rustc_middle::dep_graph::{SerializedDepGraph, WorkProductMap};
|
||||
use rustc_middle::dep_graph::{DepsType, SerializedDepGraph, WorkProductMap};
|
||||
use rustc_middle::query::on_disk_cache::OnDiskCache;
|
||||
use rustc_serialize::opaque::MemDecoder;
|
||||
use rustc_serialize::Decodable;
|
||||
@ -208,7 +208,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
|
||||
return LoadResult::DataOutOfDate;
|
||||
}
|
||||
|
||||
let dep_graph = SerializedDepGraph::decode(&mut decoder);
|
||||
let dep_graph = SerializedDepGraph::decode::<DepsType>(&mut decoder);
|
||||
|
||||
LoadResult::Ok { data: (dep_graph, prev_work_products) }
|
||||
}
|
||||
|
@ -198,6 +198,10 @@ infer_nothing = {""}
|
||||
infer_oc_cant_coerce = cannot coerce intrinsics to function pointers
|
||||
infer_oc_closure_selfref = closure/generator type that references itself
|
||||
infer_oc_const_compat = const not compatible with trait
|
||||
infer_oc_fn_lang_correct_type = {$lang_item_name ->
|
||||
[panic_impl] `#[panic_handler]`
|
||||
*[lang_item_name] lang item `{$lang_item_name}`
|
||||
} function has wrong type
|
||||
infer_oc_fn_main_correct_type = `main` function has wrong type
|
||||
infer_oc_fn_start_correct_type = `#[start]` function has wrong type
|
||||
infer_oc_generic = mismatched types
|
||||
@ -337,6 +341,7 @@ infer_subtype = ...so that the {$requirement ->
|
||||
[no_else] `if` missing an `else` returns `()`
|
||||
[fn_main_correct_type] `main` function has the correct type
|
||||
[fn_start_correct_type] `#[start]` function has the correct type
|
||||
[fn_lang_correct_type] lang item function has the correct type
|
||||
[intrinsic_correct_type] intrinsic has the correct type
|
||||
[method_correct_type] method receiver has the correct type
|
||||
*[other] types are compatible
|
||||
@ -350,6 +355,7 @@ infer_subtype_2 = ...so that {$requirement ->
|
||||
[no_else] `if` missing an `else` returns `()`
|
||||
[fn_main_correct_type] `main` function has the correct type
|
||||
[fn_start_correct_type] `#[start]` function has the correct type
|
||||
[fn_lang_correct_type] lang item function has the correct type
|
||||
[intrinsic_correct_type] intrinsic has the correct type
|
||||
[method_correct_type] method receiver has the correct type
|
||||
*[other] types are compatible
|
||||
|
@ -1463,6 +1463,14 @@ pub enum ObligationCauseFailureCode {
|
||||
#[subdiagnostic]
|
||||
subdiags: Vec<TypeErrorAdditionalDiags>,
|
||||
},
|
||||
#[diag(infer_oc_fn_lang_correct_type, code = "E0308")]
|
||||
FnLangCorrectType {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
#[subdiagnostic]
|
||||
subdiags: Vec<TypeErrorAdditionalDiags>,
|
||||
lang_item_name: Symbol,
|
||||
},
|
||||
#[diag(infer_oc_intrinsic_correct_type, code = "E0308")]
|
||||
IntrinsicCorrectType {
|
||||
#[primary_span]
|
||||
|
@ -2927,6 +2927,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
|
||||
| IfExpression { .. }
|
||||
| LetElse
|
||||
| StartFunctionType
|
||||
| LangFunctionType(_)
|
||||
| IntrinsicType
|
||||
| MethodReceiver => Error0308,
|
||||
|
||||
@ -2971,6 +2972,9 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
|
||||
LetElse => ObligationCauseFailureCode::NoDiverge { span, subdiags },
|
||||
MainFunctionType => ObligationCauseFailureCode::FnMainCorrectType { span },
|
||||
StartFunctionType => ObligationCauseFailureCode::FnStartCorrectType { span, subdiags },
|
||||
&LangFunctionType(lang_item_name) => {
|
||||
ObligationCauseFailureCode::FnLangCorrectType { span, subdiags, lang_item_name }
|
||||
}
|
||||
IntrinsicType => ObligationCauseFailureCode::IntrinsicCorrectType { span, subdiags },
|
||||
MethodReceiver => ObligationCauseFailureCode::MethodCorrectType { span, subdiags },
|
||||
|
||||
@ -3006,6 +3010,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
|
||||
IfExpressionWithNoElse => "`if` missing an `else` returns `()`",
|
||||
MainFunctionType => "`main` function has the correct type",
|
||||
StartFunctionType => "`#[start]` function has the correct type",
|
||||
LangFunctionType(_) => "lang item function has the correct type",
|
||||
IntrinsicType => "intrinsic has the correct type",
|
||||
MethodReceiver => "method receiver has the correct type",
|
||||
_ => "types are compatible",
|
||||
@ -3028,6 +3033,7 @@ impl IntoDiagnosticArg for ObligationCauseAsDiagArg<'_> {
|
||||
IfExpressionWithNoElse => "no_else",
|
||||
MainFunctionType => "fn_main_correct_type",
|
||||
StartFunctionType => "fn_start_correct_type",
|
||||
LangFunctionType(_) => "fn_lang_correct_type",
|
||||
IntrinsicType => "intrinsic_correct_type",
|
||||
MethodReceiver => "method_correct_type",
|
||||
_ => "other",
|
||||
|
@ -10,8 +10,10 @@
|
||||
//! origin crate when the `TyCtxt` is not present in TLS.
|
||||
|
||||
use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS};
|
||||
use rustc_middle::dep_graph::TaskDepsRef;
|
||||
use rustc_middle::dep_graph::{DepNodeExt, TaskDepsRef};
|
||||
use rustc_middle::ty::tls;
|
||||
use rustc_query_system::dep_graph::dep_node::default_dep_kind_debug;
|
||||
use rustc_query_system::dep_graph::{DepContext, DepKind, DepNode};
|
||||
use std::fmt;
|
||||
|
||||
fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) {
|
||||
@ -59,10 +61,49 @@ fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) ->
|
||||
write!(f, ")")
|
||||
}
|
||||
|
||||
/// This is a callback from `rustc_query_system` as it cannot access the implicit state
|
||||
/// in `rustc_middle` otherwise.
|
||||
pub fn dep_kind_debug(kind: DepKind, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
tls::with_opt(|opt_tcx| {
|
||||
if let Some(tcx) = opt_tcx {
|
||||
write!(f, "{}", tcx.dep_kind_info(kind).name)
|
||||
} else {
|
||||
default_dep_kind_debug(kind, f)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// This is a callback from `rustc_query_system` as it cannot access the implicit state
|
||||
/// in `rustc_middle` otherwise.
|
||||
pub fn dep_node_debug(node: DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}(", node.kind)?;
|
||||
|
||||
tls::with_opt(|opt_tcx| {
|
||||
if let Some(tcx) = opt_tcx {
|
||||
if let Some(def_id) = node.extract_def_id(tcx) {
|
||||
write!(f, "{}", tcx.def_path_debug_str(def_id))?;
|
||||
} else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(node) {
|
||||
write!(f, "{s}")?;
|
||||
} else {
|
||||
write!(f, "{}", node.hash)?;
|
||||
}
|
||||
} else {
|
||||
write!(f, "{}", node.hash)?;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
write!(f, ")")
|
||||
}
|
||||
|
||||
/// Sets up the callbacks in prior crates which we want to refer to the
|
||||
/// TyCtxt in.
|
||||
pub fn setup_callbacks() {
|
||||
rustc_span::SPAN_TRACK.swap(&(track_span_parent as fn(_)));
|
||||
rustc_hir::def_id::DEF_ID_DEBUG.swap(&(def_id_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
|
||||
rustc_query_system::dep_graph::dep_node::DEP_KIND_DEBUG
|
||||
.swap(&(dep_kind_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
|
||||
rustc_query_system::dep_graph::dep_node::DEP_NODE_DEBUG
|
||||
.swap(&(dep_node_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
|
||||
TRACK_DIAGNOSTICS.swap(&(track_diagnostic as _));
|
||||
}
|
||||
|
@ -41,7 +41,6 @@ use crate::{
|
||||
},
|
||||
EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext,
|
||||
};
|
||||
use hir::IsAsync;
|
||||
use rustc_ast::attr;
|
||||
use rustc_ast::tokenstream::{TokenStream, TokenTree};
|
||||
use rustc_ast::visit::{FnCtxt, FnKind};
|
||||
@ -1294,7 +1293,7 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller {
|
||||
span: Span,
|
||||
def_id: LocalDefId,
|
||||
) {
|
||||
if fn_kind.asyncness() == IsAsync::Async
|
||||
if fn_kind.asyncness().is_async()
|
||||
&& !cx.tcx.features().async_fn_track_caller
|
||||
// Now, check if the function has the `#[track_caller]` attribute
|
||||
&& let Some(attr) = cx.tcx.get_attr(def_id, sym::track_caller)
|
||||
|
@ -1315,6 +1315,54 @@ impl<'tcx> LateContext<'tcx> {
|
||||
tcx.try_normalize_erasing_regions(self.param_env, proj).ok()
|
||||
})
|
||||
}
|
||||
|
||||
/// If the given expression is a local binding, find the initializer expression.
|
||||
/// If that initializer expression is another local or **outside** (`const`/`static`)
|
||||
/// binding, find its initializer again.
|
||||
///
|
||||
/// This process repeats as long as possible (but usually no more than once).
|
||||
/// Type-check adjustments are not taken in account in this function.
|
||||
///
|
||||
/// Examples:
|
||||
/// ```
|
||||
/// const ABC: i32 = 1;
|
||||
/// // ^ output
|
||||
/// let def = ABC;
|
||||
/// dbg!(def);
|
||||
/// // ^^^ input
|
||||
///
|
||||
/// // or...
|
||||
/// let abc = 1;
|
||||
/// let def = abc + 2;
|
||||
/// // ^^^^^^^ output
|
||||
/// dbg!(def);
|
||||
/// // ^^^ input
|
||||
/// ```
|
||||
pub fn expr_or_init<'a>(&self, mut expr: &'a hir::Expr<'tcx>) -> &'a hir::Expr<'tcx> {
|
||||
expr = expr.peel_blocks();
|
||||
|
||||
while let hir::ExprKind::Path(ref qpath) = expr.kind
|
||||
&& let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
|
||||
Res::Local(hir_id) => self.tcx.hir().find_parent(hir_id),
|
||||
Res::Def(_, def_id) => self.tcx.hir().get_if_local(def_id),
|
||||
_ => None,
|
||||
}
|
||||
&& let Some(init) = match parent_node {
|
||||
hir::Node::Expr(expr) => Some(expr),
|
||||
hir::Node::Local(hir::Local { init, .. }) => *init,
|
||||
hir::Node::Item(item) => match item.kind {
|
||||
hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => {
|
||||
Some(self.tcx.hir().body(body_id).value)
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
{
|
||||
expr = init.peel_blocks();
|
||||
}
|
||||
expr
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> abi::HasDataLayout for LateContext<'tcx> {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::str::Utf8Error;
|
||||
|
||||
use rustc_ast::{BorrowKind, LitKind};
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::sym;
|
||||
@ -11,7 +11,7 @@ use crate::{LateContext, LateLintPass, LintContext};
|
||||
declare_lint! {
|
||||
/// The `invalid_from_utf8_unchecked` lint checks for calls to
|
||||
/// `std::str::from_utf8_unchecked` and `std::str::from_utf8_unchecked_mut`
|
||||
/// with an invalid UTF-8 literal.
|
||||
/// with a known invalid UTF-8 value.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
@ -36,7 +36,7 @@ declare_lint! {
|
||||
declare_lint! {
|
||||
/// The `invalid_from_utf8` lint checks for calls to
|
||||
/// `std::str::from_utf8` and `std::str::from_utf8_mut`
|
||||
/// with an invalid UTF-8 literal.
|
||||
/// with a known invalid UTF-8 value.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
@ -67,8 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 {
|
||||
&& [sym::str_from_utf8, sym::str_from_utf8_mut,
|
||||
sym::str_from_utf8_unchecked, sym::str_from_utf8_unchecked_mut].contains(&diag_item)
|
||||
{
|
||||
let lint = |utf8_error: Utf8Error| {
|
||||
let label = arg.span;
|
||||
let lint = |label, utf8_error: Utf8Error| {
|
||||
let method = diag_item.as_str().strip_prefix("str_").unwrap();
|
||||
let method = format!("std::str::{method}");
|
||||
let valid_up_to = utf8_error.valid_up_to();
|
||||
@ -78,22 +77,26 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 {
|
||||
if is_unchecked_variant { INVALID_FROM_UTF8_UNCHECKED } else { INVALID_FROM_UTF8 },
|
||||
expr.span,
|
||||
if is_unchecked_variant {
|
||||
InvalidFromUtf8Diag::Unchecked { method, valid_up_to, label }
|
||||
InvalidFromUtf8Diag::Unchecked { method, valid_up_to, label }
|
||||
} else {
|
||||
InvalidFromUtf8Diag::Checked { method, valid_up_to, label }
|
||||
InvalidFromUtf8Diag::Checked { method, valid_up_to, label }
|
||||
}
|
||||
)
|
||||
};
|
||||
|
||||
match &arg.kind {
|
||||
let mut init = cx.expr_or_init(arg);
|
||||
while let ExprKind::AddrOf(.., inner) = init.kind {
|
||||
init = cx.expr_or_init(inner);
|
||||
}
|
||||
match init.kind {
|
||||
ExprKind::Lit(Spanned { node: lit, .. }) => {
|
||||
if let LitKind::ByteStr(bytes, _) = &lit
|
||||
&& let Err(utf8_error) = std::str::from_utf8(bytes)
|
||||
{
|
||||
lint(utf8_error);
|
||||
lint(init.span, utf8_error);
|
||||
}
|
||||
},
|
||||
ExprKind::AddrOf(BorrowKind::Ref, _, Expr { kind: ExprKind::Array(args), .. }) => {
|
||||
ExprKind::Array(args) => {
|
||||
let elements = args.iter().map(|e|{
|
||||
match &e.kind {
|
||||
ExprKind::Lit(Spanned { node: lit, .. }) => match lit {
|
||||
@ -108,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidFromUtf8 {
|
||||
if let Some(elements) = elements
|
||||
&& let Err(utf8_error) = std::str::from_utf8(&elements)
|
||||
{
|
||||
lint(utf8_error);
|
||||
lint(init.span, utf8_error);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
@ -126,8 +126,8 @@ macro_rules! provide_one {
|
||||
// External query providers call `crate_hash` in order to register a dependency
|
||||
// on the crate metadata. The exception is `crate_hash` itself, which obviously
|
||||
// doesn't need to do this (and can't, as it would cause a query cycle).
|
||||
use rustc_middle::dep_graph::DepKind;
|
||||
if DepKind::$name != DepKind::crate_hash && $tcx.dep_graph.is_fully_enabled() {
|
||||
use rustc_middle::dep_graph::dep_kinds;
|
||||
if dep_kinds::$name != dep_kinds::crate_hash && $tcx.dep_graph.is_fully_enabled() {
|
||||
$tcx.ensure().crate_hash($def_id.krate);
|
||||
}
|
||||
|
||||
|
@ -439,7 +439,7 @@ define_tables! {
|
||||
coerce_unsized_info: Table<DefIndex, LazyValue<ty::adjustment::CoerceUnsizedInfo>>,
|
||||
mir_const_qualif: Table<DefIndex, LazyValue<mir::ConstQualifs>>,
|
||||
rendered_const: Table<DefIndex, LazyValue<String>>,
|
||||
asyncness: Table<DefIndex, hir::IsAsync>,
|
||||
asyncness: Table<DefIndex, ty::Asyncness>,
|
||||
fn_arg_names: Table<DefIndex, LazyArray<Ident>>,
|
||||
generator_kind: Table<DefIndex, LazyValue<hir::GeneratorKind>>,
|
||||
trait_def: Table<DefIndex, LazyValue<ty::TraitDef>>,
|
||||
|
@ -205,9 +205,9 @@ fixed_size_enum! {
|
||||
}
|
||||
|
||||
fixed_size_enum! {
|
||||
hir::IsAsync {
|
||||
( NotAsync )
|
||||
( Async )
|
||||
ty::Asyncness {
|
||||
( Yes )
|
||||
( No )
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,9 +65,9 @@ use rustc_hir::definitions::DefPathHash;
|
||||
use rustc_hir::{HirId, ItemLocalId, OwnerId};
|
||||
use rustc_query_system::dep_graph::FingerprintStyle;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use std::hash::Hash;
|
||||
|
||||
pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams};
|
||||
pub use rustc_query_system::dep_graph::dep_node::DepKind;
|
||||
pub use rustc_query_system::dep_graph::{DepContext, DepNode, DepNodeParams};
|
||||
|
||||
macro_rules! define_dep_nodes {
|
||||
(
|
||||
@ -84,55 +84,39 @@ macro_rules! define_dep_nodes {
|
||||
// encoding. The derived Encodable/Decodable uses leb128 encoding which is
|
||||
// dense when only considering this enum. But DepKind is encoded in a larger
|
||||
// struct, and there we can take advantage of the unused bits in the u16.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(u16)]
|
||||
pub enum DepKind {
|
||||
#[repr(u16)] // Must be kept in sync with the inner type of `DepKind`.
|
||||
enum DepKindDefs {
|
||||
$( $( #[$attr] )* $variant),*
|
||||
}
|
||||
|
||||
impl DepKind {
|
||||
// This const implements two things: A bounds check so that we can decode
|
||||
// a DepKind from a u16 with just one check, and a const check that the
|
||||
// discriminants of the variants have been assigned consecutively from 0
|
||||
// so that just the one comparison suffices to check that the u16 can be
|
||||
// transmuted to a DepKind.
|
||||
pub const VARIANTS: u16 = {
|
||||
let deps: &[DepKind] = &[$(DepKind::$variant,)*];
|
||||
let mut i = 0;
|
||||
while i < deps.len() {
|
||||
if i as u16 != deps[i] as u16 {
|
||||
panic!();
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
deps.len() as u16
|
||||
};
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub mod dep_kinds {
|
||||
use super::*;
|
||||
|
||||
$(
|
||||
// The `as u16` cast must be kept in sync with the inner type of `DepKind`.
|
||||
pub const $variant: DepKind = DepKind::new(DepKindDefs::$variant as u16);
|
||||
)*
|
||||
}
|
||||
|
||||
impl<S: rustc_serialize::Encoder> rustc_serialize::Encodable<S> for DepKind {
|
||||
#[inline]
|
||||
fn encode(&self, s: &mut S) {
|
||||
s.emit_u16(*self as u16);
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: rustc_serialize::Decoder> rustc_serialize::Decodable<D> for DepKind {
|
||||
#[inline]
|
||||
fn decode(d: &mut D) -> DepKind {
|
||||
let discrim = d.read_u16();
|
||||
assert!(discrim < DepKind::VARIANTS);
|
||||
// SAFETY: DepKind::VARIANTS checks that the discriminant values permit
|
||||
// this one check to soundly guard the transmute.
|
||||
unsafe {
|
||||
std::mem::transmute::<u16, DepKind>(discrim)
|
||||
// This checks that the discriminants of the variants have been assigned consecutively
|
||||
// from 0 so that they can be used as a dense index.
|
||||
pub const DEP_KIND_VARIANTS: u16 = {
|
||||
let deps = &[$(dep_kinds::$variant,)*];
|
||||
let mut i = 0;
|
||||
while i < deps.len() {
|
||||
if i != deps[i].as_usize() {
|
||||
panic!();
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
deps.len() as u16
|
||||
};
|
||||
|
||||
pub(super) fn dep_kind_from_label_string(label: &str) -> Result<DepKind, ()> {
|
||||
match label {
|
||||
$(stringify!($variant) => Ok(DepKind::$variant),)*
|
||||
$(stringify!($variant) => Ok(dep_kinds::$variant),)*
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
@ -158,12 +142,10 @@ rustc_query_append!(define_dep_nodes![
|
||||
[] fn CompileMonoItem() -> (),
|
||||
]);
|
||||
|
||||
static_assert_size!(DepKind, 2);
|
||||
|
||||
// WARNING: `construct` is generic and does not know that `CompileCodegenUnit` takes `Symbol`s as keys.
|
||||
// Be very careful changing this type signature!
|
||||
pub(crate) fn make_compile_codegen_unit(tcx: TyCtxt<'_>, name: Symbol) -> DepNode {
|
||||
DepNode::construct(tcx, DepKind::CompileCodegenUnit, &name)
|
||||
DepNode::construct(tcx, dep_kinds::CompileCodegenUnit, &name)
|
||||
}
|
||||
|
||||
// WARNING: `construct` is generic and does not know that `CompileMonoItem` takes `MonoItem`s as keys.
|
||||
@ -172,20 +154,9 @@ pub(crate) fn make_compile_mono_item<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
mono_item: &MonoItem<'tcx>,
|
||||
) -> DepNode {
|
||||
DepNode::construct(tcx, DepKind::CompileMonoItem, mono_item)
|
||||
DepNode::construct(tcx, dep_kinds::CompileMonoItem, mono_item)
|
||||
}
|
||||
|
||||
pub type DepNode = rustc_query_system::dep_graph::DepNode<DepKind>;
|
||||
|
||||
// We keep a lot of `DepNode`s in memory during compilation. It's not
|
||||
// required that their size stay the same, but we don't want to change
|
||||
// it inadvertently. This assert just ensures we're aware of any change.
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
static_assert_size!(DepNode, 18);
|
||||
|
||||
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
static_assert_size!(DepNode, 24);
|
||||
|
||||
pub trait DepNodeExt: Sized {
|
||||
/// Extracts the DefId corresponding to this DepNode. This will work
|
||||
/// if two conditions are met:
|
||||
|
@ -6,49 +6,24 @@ use rustc_session::Session;
|
||||
#[macro_use]
|
||||
mod dep_node;
|
||||
|
||||
pub use rustc_query_system::dep_graph::debug::EdgeFilter;
|
||||
pub use rustc_query_system::dep_graph::{
|
||||
debug::DepNodeFilter, hash_result, DepContext, DepNodeColor, DepNodeIndex,
|
||||
SerializedDepNodeIndex, WorkProduct, WorkProductId, WorkProductMap,
|
||||
debug::DepNodeFilter, hash_result, DepContext, DepGraphQuery, DepNodeColor, DepNodeIndex, Deps,
|
||||
SerializedDepGraph, SerializedDepNodeIndex, TaskDeps, TaskDepsRef, WorkProduct, WorkProductId,
|
||||
WorkProductMap,
|
||||
};
|
||||
|
||||
pub use dep_node::{label_strs, DepKind, DepNode, DepNodeExt};
|
||||
pub use dep_node::{dep_kinds, label_strs, DepKind, DepNode, DepNodeExt};
|
||||
pub(crate) use dep_node::{make_compile_codegen_unit, make_compile_mono_item};
|
||||
|
||||
pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>;
|
||||
pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepsType>;
|
||||
|
||||
pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>;
|
||||
pub type TaskDepsRef<'a> = rustc_query_system::dep_graph::TaskDepsRef<'a, DepKind>;
|
||||
pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery<DepKind>;
|
||||
pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph<DepKind>;
|
||||
pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter<DepKind>;
|
||||
pub type DepKindStruct<'tcx> = rustc_query_system::dep_graph::DepKindStruct<TyCtxt<'tcx>>;
|
||||
|
||||
impl rustc_query_system::dep_graph::DepKind for DepKind {
|
||||
const NULL: Self = DepKind::Null;
|
||||
const RED: Self = DepKind::Red;
|
||||
const MAX: u16 = DepKind::VARIANTS - 1;
|
||||
|
||||
fn debug_node(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}(", node.kind)?;
|
||||
|
||||
ty::tls::with_opt(|opt_tcx| {
|
||||
if let Some(tcx) = opt_tcx {
|
||||
if let Some(def_id) = node.extract_def_id(tcx) {
|
||||
write!(f, "{}", tcx.def_path_debug_str(def_id))?;
|
||||
} else if let Some(ref s) = tcx.dep_graph.dep_node_debug_str(*node) {
|
||||
write!(f, "{s}")?;
|
||||
} else {
|
||||
write!(f, "{}", node.hash)?;
|
||||
}
|
||||
} else {
|
||||
write!(f, "{}", node.hash)?;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
write!(f, ")")
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub struct DepsType;
|
||||
|
||||
impl Deps for DepsType {
|
||||
fn with_deps<OP, R>(task_deps: TaskDepsRef<'_>, op: OP) -> R
|
||||
where
|
||||
OP: FnOnce() -> R,
|
||||
@ -70,24 +45,13 @@ impl rustc_query_system::dep_graph::DepKind for DepKind {
|
||||
})
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
#[inline]
|
||||
fn from_u16(u: u16) -> Self {
|
||||
if u > Self::MAX {
|
||||
panic!("Invalid DepKind {u}");
|
||||
}
|
||||
// SAFETY: See comment on DepKind::VARIANTS
|
||||
unsafe { std::mem::transmute(u) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn to_u16(self) -> u16 {
|
||||
self as u16
|
||||
}
|
||||
const DEP_KIND_NULL: DepKind = dep_kinds::Null;
|
||||
const DEP_KIND_RED: DepKind = dep_kinds::Red;
|
||||
const DEP_KIND_MAX: u16 = dep_node::DEP_KIND_VARIANTS - 1;
|
||||
}
|
||||
|
||||
impl<'tcx> DepContext for TyCtxt<'tcx> {
|
||||
type DepKind = DepKind;
|
||||
type Deps = DepsType;
|
||||
|
||||
#[inline]
|
||||
fn with_stable_hashing_context<R>(self, f: impl FnOnce(StableHashingContext<'_>) -> R) -> R {
|
||||
@ -111,6 +75,6 @@ impl<'tcx> DepContext for TyCtxt<'tcx> {
|
||||
|
||||
#[inline]
|
||||
fn dep_kind_info(&self, dk: DepKind) -> &DepKindStruct<'tcx> {
|
||||
&self.query_kinds[dk as usize]
|
||||
&self.query_kinds[dk.as_usize()]
|
||||
}
|
||||
}
|
||||
|
@ -442,9 +442,10 @@ impl<'hir> Map<'hir> {
|
||||
/// Panics if `LocalDefId` does not have an associated body.
|
||||
pub fn body_owner_kind(self, def_id: LocalDefId) -> BodyOwnerKind {
|
||||
match self.tcx.def_kind(def_id) {
|
||||
DefKind::Const | DefKind::AssocConst | DefKind::InlineConst | DefKind::AnonConst => {
|
||||
BodyOwnerKind::Const
|
||||
DefKind::Const | DefKind::AssocConst | DefKind::AnonConst => {
|
||||
BodyOwnerKind::Const { inline: false }
|
||||
}
|
||||
DefKind::InlineConst => BodyOwnerKind::Const { inline: true },
|
||||
DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => BodyOwnerKind::Fn,
|
||||
DefKind::Closure | DefKind::Generator => BodyOwnerKind::Closure,
|
||||
DefKind::Static(mt) => BodyOwnerKind::Static(mt),
|
||||
@ -461,7 +462,7 @@ impl<'hir> Map<'hir> {
|
||||
/// just that it has to be checked as if it were.
|
||||
pub fn body_const_context(self, def_id: LocalDefId) -> Option<ConstContext> {
|
||||
let ccx = match self.body_owner_kind(def_id) {
|
||||
BodyOwnerKind::Const => ConstContext::Const,
|
||||
BodyOwnerKind::Const { inline } => ConstContext::Const { inline },
|
||||
BodyOwnerKind::Static(mt) => ConstContext::Static(mt),
|
||||
|
||||
BodyOwnerKind::Fn if self.tcx.is_constructor(def_id.to_def_id()) => return None,
|
||||
|
@ -6,13 +6,11 @@ use rustc_hir::{self as hir};
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::{HasDataLayout, Size};
|
||||
|
||||
use crate::mir::interpret::{
|
||||
alloc_range, AllocId, ConstAllocation, ErrorHandled, GlobalAlloc, Scalar,
|
||||
};
|
||||
use crate::mir::interpret::{alloc_range, AllocId, ConstAllocation, ErrorHandled, Scalar};
|
||||
use crate::mir::{pretty_print_const_value, Promoted};
|
||||
use crate::ty::ScalarInt;
|
||||
use crate::ty::{self, print::pretty_print_const, List, Ty, TyCtxt};
|
||||
use crate::ty::{GenericArgs, GenericArgsRef};
|
||||
use crate::ty::{ScalarInt, UserTypeAnnotationIndex};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// Evaluated Constants
|
||||
@ -178,29 +176,10 @@ impl<'tcx> ConstValue<'tcx> {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// Constants
|
||||
///
|
||||
/// Two constants are equal if they are the same constant. Note that
|
||||
/// this does not necessarily mean that they are `==` in Rust. In
|
||||
/// particular, one must be wary of `NaN`!
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub struct Constant<'tcx> {
|
||||
pub span: Span,
|
||||
|
||||
/// Optional user-given type: for something like
|
||||
/// `collect::<Vec<_>>`, this would be present and would
|
||||
/// indicate that `Vec<_>` was explicitly specified.
|
||||
///
|
||||
/// Needed for NLL to impose user-given type constraints.
|
||||
pub user_ty: Option<UserTypeAnnotationIndex>,
|
||||
|
||||
pub literal: ConstantKind<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub enum ConstantKind<'tcx> {
|
||||
pub enum Const<'tcx> {
|
||||
/// This constant came from the type system.
|
||||
///
|
||||
/// Any way of turning `ty::Const` into `ConstValue` should go through `valtree_to_const_val`;
|
||||
@ -221,46 +200,27 @@ pub enum ConstantKind<'tcx> {
|
||||
Val(ConstValue<'tcx>, Ty<'tcx>),
|
||||
}
|
||||
|
||||
impl<'tcx> Constant<'tcx> {
|
||||
pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
|
||||
match self.literal.try_to_scalar() {
|
||||
Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) {
|
||||
GlobalAlloc::Static(def_id) => {
|
||||
assert!(!tcx.is_thread_local_static(def_id));
|
||||
Some(def_id)
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn ty(&self) -> Ty<'tcx> {
|
||||
self.literal.ty()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ConstantKind<'tcx> {
|
||||
impl<'tcx> Const<'tcx> {
|
||||
#[inline(always)]
|
||||
pub fn ty(&self) -> Ty<'tcx> {
|
||||
match self {
|
||||
ConstantKind::Ty(c) => c.ty(),
|
||||
ConstantKind::Val(_, ty) | ConstantKind::Unevaluated(_, ty) => *ty,
|
||||
Const::Ty(c) => c.ty(),
|
||||
Const::Val(_, ty) | Const::Unevaluated(_, ty) => *ty,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_to_scalar(self) -> Option<Scalar> {
|
||||
match self {
|
||||
ConstantKind::Ty(c) => match c.kind() {
|
||||
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,
|
||||
},
|
||||
_ => None,
|
||||
},
|
||||
ConstantKind::Val(val, _) => val.try_to_scalar(),
|
||||
ConstantKind::Unevaluated(..) => None,
|
||||
Const::Val(val, _) => val.try_to_scalar(),
|
||||
Const::Unevaluated(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -287,17 +247,17 @@ impl<'tcx> ConstantKind<'tcx> {
|
||||
span: Option<Span>,
|
||||
) -> Result<ConstValue<'tcx>, ErrorHandled> {
|
||||
match self {
|
||||
ConstantKind::Ty(c) => {
|
||||
Const::Ty(c) => {
|
||||
// We want to consistently have a "clean" value for type system constants (i.e., no
|
||||
// data hidden in the padding), so we always go through a valtree here.
|
||||
let val = c.eval(tcx, param_env, span)?;
|
||||
Ok(tcx.valtree_to_const_val((self.ty(), val)))
|
||||
}
|
||||
ConstantKind::Unevaluated(uneval, _) => {
|
||||
Const::Unevaluated(uneval, _) => {
|
||||
// FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
|
||||
tcx.const_eval_resolve(param_env, uneval, span)
|
||||
}
|
||||
ConstantKind::Val(val, _) => Ok(val),
|
||||
Const::Val(val, _) => Ok(val),
|
||||
}
|
||||
}
|
||||
|
||||
@ -332,23 +292,18 @@ impl<'tcx> ConstantKind<'tcx> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn try_eval_bits(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Option<u128> {
|
||||
pub fn try_eval_bits(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<u128> {
|
||||
let int = self.try_eval_scalar_int(tcx, param_env)?;
|
||||
assert_eq!(self.ty(), ty);
|
||||
let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
|
||||
let size =
|
||||
tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(self.ty())).ok()?.size;
|
||||
int.to_bits(size).ok()
|
||||
}
|
||||
|
||||
/// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
|
||||
#[inline]
|
||||
pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
|
||||
self.try_eval_bits(tcx, param_env, ty)
|
||||
.unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
|
||||
pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> u128 {
|
||||
self.try_eval_bits(tcx, param_env)
|
||||
.unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", self.ty(), self))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -416,7 +371,7 @@ impl<'tcx> ConstantKind<'tcx> {
|
||||
Self::Val(val, ty)
|
||||
}
|
||||
|
||||
/// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly
|
||||
/// Literals are converted to `Const::Val`, const generic parameters are eagerly
|
||||
/// converted to a constant, everything else becomes `Unevaluated`.
|
||||
#[instrument(skip(tcx), level = "debug", ret)]
|
||||
pub fn from_anon_const(
|
||||
@ -552,29 +507,13 @@ impl<'tcx> UnevaluatedConst<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Debug for Constant<'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(fmt, "{self}")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Display for Constant<'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self.ty().kind() {
|
||||
ty::FnDef(..) => {}
|
||||
_ => write!(fmt, "const ")?,
|
||||
}
|
||||
Display::fmt(&self.literal, fmt)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Display for ConstantKind<'tcx> {
|
||||
impl<'tcx> Display for Const<'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
match *self {
|
||||
ConstantKind::Ty(c) => pretty_print_const(c, fmt, true),
|
||||
ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt),
|
||||
Const::Ty(c) => pretty_print_const(c, fmt, true),
|
||||
Const::Val(val, ty) => pretty_print_const_value(val, ty, fmt),
|
||||
// FIXME(valtrees): Correctly print mir constants.
|
||||
ConstantKind::Unevaluated(..) => {
|
||||
Const::Unevaluated(..) => {
|
||||
fmt.write_str("_")?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -45,16 +45,6 @@ impl ExpressionId {
|
||||
}
|
||||
}
|
||||
|
||||
rustc_index::newtype_index! {
|
||||
/// MappedExpressionIndex values ascend from zero, and are recalculated indexes based on their
|
||||
/// array position in the LLVM coverage map "Expressions" array, which is assembled during the
|
||||
/// "mapgen" process. They cannot be computed algorithmically, from the other `newtype_index`s.
|
||||
#[derive(HashStable)]
|
||||
#[max = 0xFFFF_FFFF]
|
||||
#[debug_format = "MappedExpressionIndex({})"]
|
||||
pub struct MappedExpressionIndex {}
|
||||
}
|
||||
|
||||
/// Operand of a coverage-counter expression.
|
||||
///
|
||||
/// Operands can be a constant zero value, an actual coverage counter, or another
|
||||
|
@ -318,7 +318,7 @@ pub struct Body<'tcx> {
|
||||
|
||||
/// Constants that are required to evaluate successfully for this MIR to be well-formed.
|
||||
/// We hold in this field all the constants we are not able to evaluate yet.
|
||||
pub required_consts: Vec<Constant<'tcx>>,
|
||||
pub required_consts: Vec<ConstOperand<'tcx>>,
|
||||
|
||||
/// Does this body use generic parameters. This is used for the `ConstEvaluatable` check.
|
||||
///
|
||||
@ -585,12 +585,12 @@ impl<'tcx> Body<'tcx> {
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
normalize_const: impl Fn(ConstantKind<'tcx>) -> Result<ConstantKind<'tcx>, ErrorHandled>,
|
||||
normalize_const: impl Fn(Const<'tcx>) -> Result<Const<'tcx>, ErrorHandled>,
|
||||
) -> Result<(), ErrorHandled> {
|
||||
// For now, the only thing we have to check is is to ensure that all the constants used in
|
||||
// the body successfully evaluate.
|
||||
for &const_ in &self.required_consts {
|
||||
let c = normalize_const(const_.literal)?;
|
||||
let c = normalize_const(const_.const_)?;
|
||||
c.eval(tcx, param_env, Some(const_.span))?;
|
||||
}
|
||||
|
||||
@ -1096,7 +1096,7 @@ impl<'tcx> LocalDecl<'tcx> {
|
||||
pub enum VarDebugInfoContents<'tcx> {
|
||||
/// This `Place` only contains projection which satisfy `can_use_in_debuginfo`.
|
||||
Place(Place<'tcx>),
|
||||
Const(Constant<'tcx>),
|
||||
Const(ConstOperand<'tcx>),
|
||||
}
|
||||
|
||||
impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
|
||||
|
@ -696,6 +696,17 @@ impl Debug for Statement<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for NonDivergingIntrinsic<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Assume(op) => write!(f, "assume({op:?})"),
|
||||
Self::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => {
|
||||
write!(f, "copy_nonoverlapping(dst = {dst:?}, src = {src:?}, count = {count:?})")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Debug for TerminatorKind<'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
self.fmt_head(fmt)?;
|
||||
@ -1058,6 +1069,22 @@ impl<'tcx> Debug for Operand<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Debug for ConstOperand<'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(fmt, "{self}")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Display for ConstOperand<'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self.ty().kind() {
|
||||
ty::FnDef(..) => {}
|
||||
_ => write!(fmt, "const ")?,
|
||||
}
|
||||
Display::fmt(&self.const_, fmt)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Place<'_> {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
self.as_ref().fmt(fmt)
|
||||
@ -1184,10 +1211,10 @@ fn use_verbose(ty: Ty<'_>, fn_def: bool) -> bool {
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
|
||||
fn visit_constant(&mut self, constant: &Constant<'tcx>, _location: Location) {
|
||||
let Constant { span, user_ty, literal } = constant;
|
||||
if use_verbose(literal.ty(), true) {
|
||||
self.push("mir::Constant");
|
||||
fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, _location: Location) {
|
||||
let ConstOperand { span, user_ty, const_ } = constant;
|
||||
if use_verbose(const_.ty(), true) {
|
||||
self.push("mir::ConstOperand");
|
||||
self.push(&format!(
|
||||
"+ span: {}",
|
||||
self.tcx.sess.source_map().span_to_embeddable_string(*span)
|
||||
@ -1209,8 +1236,8 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
|
||||
ty::ValTree::Branch(_) => "Branch(..)".to_string(),
|
||||
};
|
||||
|
||||
let val = match literal {
|
||||
ConstantKind::Ty(ct) => match ct.kind() {
|
||||
let val = match const_ {
|
||||
Const::Ty(ct) => match ct.kind() {
|
||||
ty::ConstKind::Param(p) => format!("ty::Param({p})"),
|
||||
ty::ConstKind::Unevaluated(uv) => {
|
||||
format!("ty::Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.args,)
|
||||
@ -1222,9 +1249,9 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
|
||||
ty::ConstKind::Placeholder(_)
|
||||
| ty::ConstKind::Infer(_)
|
||||
| ty::ConstKind::Expr(_)
|
||||
| ty::ConstKind::Bound(..) => bug!("unexpected MIR constant: {:?}", literal),
|
||||
| ty::ConstKind::Bound(..) => bug!("unexpected MIR constant: {:?}", const_),
|
||||
},
|
||||
ConstantKind::Unevaluated(uv, _) => {
|
||||
Const::Unevaluated(uv, _) => {
|
||||
format!(
|
||||
"Unevaluated({}, {:?}, {:?})",
|
||||
self.tcx.def_path_str(uv.def),
|
||||
@ -1232,13 +1259,13 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
|
||||
uv.promoted,
|
||||
)
|
||||
}
|
||||
ConstantKind::Val(val, ty) => format!("Value({})", fmt_val(*val, *ty)),
|
||||
Const::Val(val, ty) => format!("Value({})", fmt_val(*val, *ty)),
|
||||
};
|
||||
|
||||
// This reflects what `Const` looked liked before `val` was renamed
|
||||
// as `kind`. We print it like this to avoid having to update
|
||||
// expected output in a lot of tests.
|
||||
self.push(&format!("+ literal: Const {{ ty: {}, val: {} }}", literal.ty(), val));
|
||||
self.push(&format!("+ const_: Const {{ ty: {}, val: {} }}", const_.ty(), val));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1312,10 +1339,10 @@ pub fn write_allocations<'tcx>(
|
||||
struct CollectAllocIds(BTreeSet<AllocId>);
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for CollectAllocIds {
|
||||
fn visit_constant(&mut self, c: &Constant<'tcx>, _: Location) {
|
||||
match c.literal {
|
||||
ConstantKind::Ty(_) | ConstantKind::Unevaluated(..) => {}
|
||||
ConstantKind::Val(val, _) => {
|
||||
fn visit_constant(&mut self, c: &ConstOperand<'tcx>, _: Location) {
|
||||
match c.const_ {
|
||||
Const::Ty(_) | Const::Unevaluated(..) => {}
|
||||
Const::Val(val, _) => {
|
||||
self.0.extend(alloc_ids_from_const_val(val));
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/// Functionality for statements, operands, places, and things that appear in them.
|
||||
use super::*;
|
||||
use super::{interpret::GlobalAlloc, *};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Statements
|
||||
@ -302,10 +302,10 @@ impl<'tcx> Operand<'tcx> {
|
||||
span: Span,
|
||||
) -> Self {
|
||||
let ty = Ty::new_fn_def(tcx, def_id, args);
|
||||
Operand::Constant(Box::new(Constant {
|
||||
Operand::Constant(Box::new(ConstOperand {
|
||||
span,
|
||||
user_ty: None,
|
||||
literal: ConstantKind::Val(ConstValue::ZeroSized, ty),
|
||||
const_: Const::Val(ConstValue::ZeroSized, ty),
|
||||
}))
|
||||
}
|
||||
|
||||
@ -333,10 +333,10 @@ impl<'tcx> Operand<'tcx> {
|
||||
};
|
||||
scalar_size == type_size
|
||||
});
|
||||
Operand::Constant(Box::new(Constant {
|
||||
Operand::Constant(Box::new(ConstOperand {
|
||||
span,
|
||||
user_ty: None,
|
||||
literal: ConstantKind::Val(ConstValue::Scalar(val), ty),
|
||||
const_: Const::Val(ConstValue::Scalar(val), ty),
|
||||
}))
|
||||
}
|
||||
|
||||
@ -356,9 +356,9 @@ impl<'tcx> Operand<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the `Constant` that is the target of this `Operand`, or `None` if this `Operand` is a
|
||||
/// Returns the `ConstOperand` that is the target of this `Operand`, or `None` if this `Operand` is a
|
||||
/// place.
|
||||
pub fn constant(&self) -> Option<&Constant<'tcx>> {
|
||||
pub fn constant(&self) -> Option<&ConstOperand<'tcx>> {
|
||||
match self {
|
||||
Operand::Constant(x) => Some(&**x),
|
||||
Operand::Copy(_) | Operand::Move(_) => None,
|
||||
@ -370,11 +370,31 @@ impl<'tcx> Operand<'tcx> {
|
||||
/// While this is unlikely in general, it's the normal case of what you'll
|
||||
/// find as the `func` in a [`TerminatorKind::Call`].
|
||||
pub fn const_fn_def(&self) -> Option<(DefId, GenericArgsRef<'tcx>)> {
|
||||
let const_ty = self.constant()?.literal.ty();
|
||||
let const_ty = self.constant()?.const_.ty();
|
||||
if let ty::FnDef(def_id, args) = *const_ty.kind() { Some((def_id, args)) } else { None }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> ConstOperand<'tcx> {
|
||||
pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
|
||||
match self.const_.try_to_scalar() {
|
||||
Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) {
|
||||
GlobalAlloc::Static(def_id) => {
|
||||
assert!(!tcx.is_thread_local_static(def_id));
|
||||
Some(def_id)
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ty(&self) -> Ty<'tcx> {
|
||||
self.const_.ty()
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// Rvalues
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
//! This is in a dedicated file so that changes to this file can be reviewed more carefully.
|
||||
//! The intention is that this file only contains datatype declarations, no code.
|
||||
|
||||
use super::{BasicBlock, Constant, Local, UserTypeProjection};
|
||||
use super::{BasicBlock, Const, Local, UserTypeProjection};
|
||||
|
||||
use crate::mir::coverage::{CodeRegion, CoverageKind};
|
||||
use crate::traits::Reveal;
|
||||
@ -439,17 +439,6 @@ pub enum NonDivergingIntrinsic<'tcx> {
|
||||
CopyNonOverlapping(CopyNonOverlapping<'tcx>),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for NonDivergingIntrinsic<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Assume(op) => write!(f, "assume({op:?})"),
|
||||
Self::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => {
|
||||
write!(f, "copy_nonoverlapping(dst = {dst:?}, src = {src:?}, count = {count:?})")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes what kind of retag is to be performed.
|
||||
#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, Hash, HashStable)]
|
||||
#[rustc_pass_by_value]
|
||||
@ -913,10 +902,10 @@ pub enum InlineAsmOperand<'tcx> {
|
||||
out_place: Option<Place<'tcx>>,
|
||||
},
|
||||
Const {
|
||||
value: Box<Constant<'tcx>>,
|
||||
value: Box<ConstOperand<'tcx>>,
|
||||
},
|
||||
SymFn {
|
||||
value: Box<Constant<'tcx>>,
|
||||
value: Box<ConstOperand<'tcx>>,
|
||||
},
|
||||
SymStatic {
|
||||
def_id: DefId,
|
||||
@ -1136,7 +1125,22 @@ pub enum Operand<'tcx> {
|
||||
Move(Place<'tcx>),
|
||||
|
||||
/// Constants are already semantically values, and remain unchanged.
|
||||
Constant(Box<Constant<'tcx>>),
|
||||
Constant(Box<ConstOperand<'tcx>>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub struct ConstOperand<'tcx> {
|
||||
pub span: Span,
|
||||
|
||||
/// Optional user-given type: for something like
|
||||
/// `collect::<Vec<_>>`, this would be present and would
|
||||
/// indicate that `Vec<_>` was explicitly specified.
|
||||
///
|
||||
/// Needed for NLL to impose user-given type constraints.
|
||||
pub user_ty: Option<UserTypeAnnotationIndex>,
|
||||
|
||||
pub const_: Const<'tcx>,
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
@ -227,7 +227,7 @@ impl<'tcx> Operand<'tcx> {
|
||||
{
|
||||
match self {
|
||||
&Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty,
|
||||
Operand::Constant(c) => c.literal.ty(),
|
||||
Operand::Constant(c) => c.const_.ty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -186,7 +186,7 @@ macro_rules! make_mir_visitor {
|
||||
|
||||
fn visit_constant(
|
||||
&mut self,
|
||||
constant: & $($mutability)? Constant<'tcx>,
|
||||
constant: & $($mutability)? ConstOperand<'tcx>,
|
||||
location: Location,
|
||||
) {
|
||||
self.super_constant(constant, location);
|
||||
@ -870,20 +870,20 @@ macro_rules! make_mir_visitor {
|
||||
|
||||
fn super_constant(
|
||||
&mut self,
|
||||
constant: & $($mutability)? Constant<'tcx>,
|
||||
constant: & $($mutability)? ConstOperand<'tcx>,
|
||||
location: Location
|
||||
) {
|
||||
let Constant {
|
||||
let ConstOperand {
|
||||
span,
|
||||
user_ty: _, // no visit method for this
|
||||
literal,
|
||||
const_,
|
||||
} = constant;
|
||||
|
||||
self.visit_span($(& $mutability)? *span);
|
||||
match literal {
|
||||
ConstantKind::Ty(ct) => self.visit_ty_const($(&$mutability)? *ct, location),
|
||||
ConstantKind::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
|
||||
ConstantKind::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
|
||||
match const_ {
|
||||
Const::Ty(ct) => self.visit_ty_const($(&$mutability)? *ct, location),
|
||||
Const::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
|
||||
Const::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,9 +116,8 @@ impl EraseType for Result<ty::Const<'_>, mir::interpret::LitToConstError> {
|
||||
type Result = [u8; size_of::<Result<ty::Const<'static>, mir::interpret::LitToConstError>>()];
|
||||
}
|
||||
|
||||
impl EraseType for Result<mir::ConstantKind<'_>, mir::interpret::LitToConstError> {
|
||||
type Result =
|
||||
[u8; size_of::<Result<mir::ConstantKind<'static>, mir::interpret::LitToConstError>>()];
|
||||
impl EraseType for Result<mir::Const<'_>, mir::interpret::LitToConstError> {
|
||||
type Result = [u8; size_of::<Result<mir::Const<'static>, mir::interpret::LitToConstError>>()];
|
||||
}
|
||||
|
||||
impl EraseType for Result<mir::ConstAlloc<'_>, mir::interpret::ErrorHandled> {
|
||||
@ -266,6 +265,7 @@ trivial! {
|
||||
rustc_middle::ty::adjustment::CoerceUnsizedInfo,
|
||||
rustc_middle::ty::AssocItem,
|
||||
rustc_middle::ty::AssocItemContainer,
|
||||
rustc_middle::ty::Asyncness,
|
||||
rustc_middle::ty::BoundVariableKind,
|
||||
rustc_middle::ty::DeducedParamAttrs,
|
||||
rustc_middle::ty::Destructor,
|
||||
@ -311,7 +311,7 @@ macro_rules! tcx_lifetime {
|
||||
tcx_lifetime! {
|
||||
rustc_middle::hir::Owner,
|
||||
rustc_middle::middle::exported_symbols::ExportedSymbol,
|
||||
rustc_middle::mir::ConstantKind,
|
||||
rustc_middle::mir::Const,
|
||||
rustc_middle::mir::DestructuredConstant,
|
||||
rustc_middle::mir::ConstAlloc,
|
||||
rustc_middle::mir::ConstValue,
|
||||
|
@ -416,7 +416,7 @@ impl<'tcx> Key for GenericArg<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for mir::ConstantKind<'tcx> {
|
||||
impl<'tcx> Key for mir::Const<'tcx> {
|
||||
type CacheSelector = DefaultCacheSelector<Self>;
|
||||
|
||||
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
||||
|
@ -7,7 +7,6 @@
|
||||
#![allow(unused_parens)]
|
||||
|
||||
use crate::dep_graph;
|
||||
use crate::dep_graph::DepKind;
|
||||
use crate::infer::canonical::{self, Canonical};
|
||||
use crate::lint::LintExpectation;
|
||||
use crate::metadata::ModChild;
|
||||
@ -731,7 +730,7 @@ rustc_queries! {
|
||||
separate_provide_extern
|
||||
}
|
||||
|
||||
query asyncness(key: DefId) -> hir::IsAsync {
|
||||
query asyncness(key: DefId) -> ty::Asyncness {
|
||||
desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) }
|
||||
separate_provide_extern
|
||||
}
|
||||
@ -1101,7 +1100,7 @@ rustc_queries! {
|
||||
desc { "destructuring type level constant"}
|
||||
}
|
||||
|
||||
/// Tries to destructure an `mir::ConstantKind` ADT or array into its variant index
|
||||
/// Tries to destructure an `mir::Const` ADT or array into its variant index
|
||||
/// and its field values. This should only be used for pretty printing.
|
||||
query try_destructure_mir_constant_for_diagnostics(
|
||||
key: (mir::ConstValue<'tcx>, Ty<'tcx>)
|
||||
|
@ -37,7 +37,7 @@ pub struct DynamicQuery<'tcx, C: QueryCache> {
|
||||
pub eval_always: bool,
|
||||
pub dep_kind: DepKind,
|
||||
pub handle_cycle_error: HandleCycleError,
|
||||
pub query_state: FieldOffset<QueryStates<'tcx>, QueryState<C::Key, DepKind>>,
|
||||
pub query_state: FieldOffset<QueryStates<'tcx>, QueryState<C::Key>>,
|
||||
pub query_cache: FieldOffset<QueryCaches<'tcx>, C>,
|
||||
pub cache_on_disk: fn(tcx: TyCtxt<'tcx>, key: &C::Key) -> bool,
|
||||
pub execute_query: fn(tcx: TyCtxt<'tcx>, k: C::Key) -> C::Value,
|
||||
@ -53,7 +53,7 @@ pub struct DynamicQuery<'tcx, C: QueryCache> {
|
||||
fn(tcx: TyCtxt<'tcx>, key: &C::Key, index: SerializedDepNodeIndex) -> bool,
|
||||
pub hash_result: HashResult<C::Value>,
|
||||
pub value_from_cycle_error:
|
||||
fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>], guar: ErrorGuaranteed) -> C::Value,
|
||||
fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> C::Value,
|
||||
pub format_value: fn(&C::Value) -> String,
|
||||
}
|
||||
|
||||
@ -402,7 +402,7 @@ macro_rules! define_callbacks {
|
||||
#[derive(Default)]
|
||||
pub struct QueryStates<'tcx> {
|
||||
$(
|
||||
pub $name: QueryState<$($K)*, DepKind>,
|
||||
pub $name: QueryState<$($K)*>,
|
||||
)*
|
||||
}
|
||||
|
||||
@ -516,7 +516,7 @@ macro_rules! define_feedable {
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let dep_node = dep_graph::DepNode::construct(tcx, dep_graph::DepKind::$name, &key);
|
||||
let dep_node = dep_graph::DepNode::construct(tcx, dep_graph::dep_kinds::$name, &key);
|
||||
let dep_node_index = tcx.dep_graph.with_feed_task(
|
||||
dep_node,
|
||||
tcx,
|
||||
|
@ -563,11 +563,11 @@ pub enum InlineAsmOperand<'tcx> {
|
||||
out_expr: Option<ExprId>,
|
||||
},
|
||||
Const {
|
||||
value: mir::ConstantKind<'tcx>,
|
||||
value: mir::Const<'tcx>,
|
||||
span: Span,
|
||||
},
|
||||
SymFn {
|
||||
value: mir::ConstantKind<'tcx>,
|
||||
value: mir::Const<'tcx>,
|
||||
span: Span,
|
||||
},
|
||||
SymStatic {
|
||||
@ -739,7 +739,7 @@ pub enum PatKind<'tcx> {
|
||||
/// * Opaque constants, that must not be matched structurally. So anything that does not derive
|
||||
/// `PartialEq` and `Eq`.
|
||||
Constant {
|
||||
value: mir::ConstantKind<'tcx>,
|
||||
value: mir::Const<'tcx>,
|
||||
},
|
||||
|
||||
Range(Box<PatRange<'tcx>>),
|
||||
@ -769,8 +769,8 @@ pub enum PatKind<'tcx> {
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, HashStable)]
|
||||
pub struct PatRange<'tcx> {
|
||||
pub lo: mir::ConstantKind<'tcx>,
|
||||
pub hi: mir::ConstantKind<'tcx>,
|
||||
pub lo: mir::Const<'tcx>,
|
||||
pub hi: mir::Const<'tcx>,
|
||||
pub end: RangeEnd,
|
||||
}
|
||||
|
||||
|
@ -26,13 +26,13 @@ pub trait Visitor<'a, 'tcx: 'a>: Sized {
|
||||
walk_pat(self, pat);
|
||||
}
|
||||
|
||||
// Note: We don't have visitors for `ty::Const` and `mir::ConstantKind`
|
||||
// Note: We don't have visitors for `ty::Const` and `mir::Const`
|
||||
// (even though these types occur in THIR) for consistency and to reduce confusion,
|
||||
// since the lazy creation of constants during thir construction causes most
|
||||
// 'constants' to not be of type `ty::Const` or `mir::ConstantKind` at that
|
||||
// 'constants' to not be of type `ty::Const` or `mir::Const` at that
|
||||
// stage (they are mostly still identified by `DefId` or `hir::Lit`, see
|
||||
// the variants `Literal`, `NonHirLiteral` and `NamedConst` in `thir::ExprKind`).
|
||||
// You have to manually visit `ty::Const` and `mir::ConstantKind` through the
|
||||
// You have to manually visit `ty::Const` and `mir::Const` through the
|
||||
// other `visit*` functions.
|
||||
}
|
||||
|
||||
|
@ -378,6 +378,9 @@ pub enum ObligationCauseCode<'tcx> {
|
||||
/// `start` has wrong type
|
||||
StartFunctionType,
|
||||
|
||||
/// language function has wrong type
|
||||
LangFunctionType(Symbol),
|
||||
|
||||
/// Intrinsic has wrong type
|
||||
IntrinsicType,
|
||||
|
||||
|
@ -339,24 +339,19 @@ impl<'tcx> Const<'tcx> {
|
||||
/// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
|
||||
/// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
|
||||
/// contains const generic parameters or pointers).
|
||||
pub fn try_eval_bits(
|
||||
self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
) -> Option<u128> {
|
||||
pub fn try_eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u128> {
|
||||
let int = self.try_eval_scalar_int(tcx, param_env)?;
|
||||
assert_eq!(self.ty(), ty);
|
||||
let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
|
||||
let size =
|
||||
tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(self.ty())).ok()?.size;
|
||||
// if `ty` does not depend on generic parameters, use an empty param_env
|
||||
int.to_bits(size).ok()
|
||||
}
|
||||
|
||||
#[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: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
|
||||
self.try_eval_bits(tcx, param_env, ty)
|
||||
.unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
|
||||
pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u128 {
|
||||
self.try_eval_bits(tcx, param_env)
|
||||
.unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", self.ty(), self))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -280,6 +280,19 @@ impl fmt::Display for ImplPolarity {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable, Debug)]
|
||||
#[derive(TypeFoldable, TypeVisitable)]
|
||||
pub enum Asyncness {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
impl Asyncness {
|
||||
pub fn is_async(self) -> bool {
|
||||
matches!(self, Asyncness::Yes)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Copy, Hash, Encodable, Decodable, HashStable)]
|
||||
pub enum Visibility<Id = LocalDefId> {
|
||||
/// Visible everywhere (including in other crates).
|
||||
|
@ -62,6 +62,7 @@ trivially_parameterized_over_tcx! {
|
||||
crate::middle::resolve_bound_vars::ObjectLifetimeDefault,
|
||||
crate::mir::ConstQualifs,
|
||||
ty::AssocItemContainer,
|
||||
ty::Asyncness,
|
||||
ty::DeducedParamAttrs,
|
||||
ty::Generics,
|
||||
ty::ImplPolarity,
|
||||
|
@ -479,7 +479,6 @@ TrivialTypeTraversalImpls! {
|
||||
::rustc_target::asm::InlineAsmRegOrRegClass,
|
||||
crate::mir::coverage::CounterId,
|
||||
crate::mir::coverage::ExpressionId,
|
||||
crate::mir::coverage::MappedExpressionIndex,
|
||||
crate::mir::Local,
|
||||
crate::mir::Promoted,
|
||||
crate::traits::Reveal,
|
||||
|
@ -17,8 +17,8 @@ pub fn find_self_call<'tcx>(
|
||||
&body[block].terminator
|
||||
{
|
||||
debug!("find_self_call: func={:?}", func);
|
||||
if let Operand::Constant(box Constant { literal, .. }) = func {
|
||||
if let ty::FnDef(def_id, fn_args) = *literal.ty().kind() {
|
||||
if let Operand::Constant(box ConstOperand { const_, .. }) = func {
|
||||
if let ty::FnDef(def_id, fn_args) = *const_.ty().kind() {
|
||||
if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
|
||||
tcx.opt_associated_item(def_id)
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::dep_graph::DepKind;
|
||||
use crate::dep_graph::dep_kinds;
|
||||
use crate::query::plumbing::CyclePlaceholder;
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
|
||||
@ -13,34 +13,22 @@ use rustc_span::{ErrorGuaranteed, Span};
|
||||
|
||||
use std::fmt::Write;
|
||||
|
||||
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Ty<'_> {
|
||||
fn from_cycle_error(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
_: &[QueryInfo<DepKind>],
|
||||
guar: ErrorGuaranteed,
|
||||
) -> Self {
|
||||
impl<'tcx> Value<TyCtxt<'tcx>> for Ty<'_> {
|
||||
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo], guar: ErrorGuaranteed) -> Self {
|
||||
// SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
|
||||
// FIXME: Represent the above fact in the trait system somehow.
|
||||
unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(Ty::new_error(tcx, guar)) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
|
||||
fn from_cycle_error(
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
_: &[QueryInfo<DepKind>],
|
||||
guar: ErrorGuaranteed,
|
||||
) -> Self {
|
||||
impl<'tcx> Value<TyCtxt<'tcx>> for Result<ty::EarlyBinder<Ty<'_>>, CyclePlaceholder> {
|
||||
fn from_cycle_error(_tcx: TyCtxt<'tcx>, _: &[QueryInfo], guar: ErrorGuaranteed) -> Self {
|
||||
Err(CyclePlaceholder(guar))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::SymbolName<'_> {
|
||||
fn from_cycle_error(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
_: &[QueryInfo<DepKind>],
|
||||
_guar: ErrorGuaranteed,
|
||||
) -> Self {
|
||||
impl<'tcx> Value<TyCtxt<'tcx>> for ty::SymbolName<'_> {
|
||||
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo], _guar: ErrorGuaranteed) -> Self {
|
||||
// SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`.
|
||||
// FIXME: Represent the above fact in the trait system somehow.
|
||||
unsafe {
|
||||
@ -51,16 +39,12 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::SymbolName<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::Binder<'_, ty::FnSig<'_>> {
|
||||
fn from_cycle_error(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
stack: &[QueryInfo<DepKind>],
|
||||
guar: ErrorGuaranteed,
|
||||
) -> Self {
|
||||
impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> {
|
||||
fn from_cycle_error(tcx: TyCtxt<'tcx>, stack: &[QueryInfo], guar: ErrorGuaranteed) -> Self {
|
||||
let err = Ty::new_error(tcx, guar);
|
||||
|
||||
let arity = if let Some(frame) = stack.get(0)
|
||||
&& frame.query.dep_kind == DepKind::fn_sig
|
||||
&& frame.query.dep_kind == dep_kinds::fn_sig
|
||||
&& let Some(def_id) = frame.query.def_id
|
||||
&& let Some(node) = tcx.hir().get_if_local(def_id)
|
||||
&& let Some(sig) = node.fn_sig()
|
||||
@ -85,16 +69,12 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::Binder<'_, ty::FnSig<'_>> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability {
|
||||
fn from_cycle_error(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
cycle: &[QueryInfo<DepKind>],
|
||||
_guar: ErrorGuaranteed,
|
||||
) -> Self {
|
||||
impl<'tcx> Value<TyCtxt<'tcx>> for Representability {
|
||||
fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], _guar: ErrorGuaranteed) -> Self {
|
||||
let mut item_and_field_ids = Vec::new();
|
||||
let mut representable_ids = FxHashSet::default();
|
||||
for info in cycle {
|
||||
if info.query.dep_kind == DepKind::representability
|
||||
if info.query.dep_kind == dep_kinds::representability
|
||||
&& let Some(field_id) = info.query.def_id
|
||||
&& let Some(field_id) = field_id.as_local()
|
||||
&& let Some(DefKind::Field) = info.query.def_kind
|
||||
@ -108,7 +88,7 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability {
|
||||
}
|
||||
}
|
||||
for info in cycle {
|
||||
if info.query.dep_kind == DepKind::representability_adt_ty
|
||||
if info.query.dep_kind == dep_kinds::representability_adt_ty
|
||||
&& let Some(def_id) = info.query.ty_adt_id
|
||||
&& let Some(def_id) = def_id.as_local()
|
||||
&& !item_and_field_ids.iter().any(|&(id, _)| id == def_id)
|
||||
@ -121,32 +101,20 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<Ty<'_>> {
|
||||
fn from_cycle_error(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
cycle: &[QueryInfo<DepKind>],
|
||||
guar: ErrorGuaranteed,
|
||||
) -> Self {
|
||||
impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<Ty<'_>> {
|
||||
fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self {
|
||||
ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle, guar))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> {
|
||||
fn from_cycle_error(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
cycle: &[QueryInfo<DepKind>],
|
||||
guar: ErrorGuaranteed,
|
||||
) -> Self {
|
||||
impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> {
|
||||
fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo], guar: ErrorGuaranteed) -> Self {
|
||||
ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle, guar))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx, T> Value<TyCtxt<'tcx>, DepKind> for Result<T, &'_ ty::layout::LayoutError<'_>> {
|
||||
fn from_cycle_error(
|
||||
_tcx: TyCtxt<'tcx>,
|
||||
_cycle: &[QueryInfo<DepKind>],
|
||||
_guar: ErrorGuaranteed,
|
||||
) -> Self {
|
||||
impl<'tcx, T> Value<TyCtxt<'tcx>> for Result<T, &'_ ty::layout::LayoutError<'_>> {
|
||||
fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo], _guar: ErrorGuaranteed) -> Self {
|
||||
// tcx.arena.alloc cannot be used because we are not allowed to use &'tcx LayoutError under
|
||||
// min_specialization. Since this is an error path anyways, leaking doesn't matter (and really,
|
||||
// tcx.arena.alloc is pretty much equal to leaking).
|
||||
|
@ -49,7 +49,7 @@ impl<'tcx> CFG<'tcx> {
|
||||
block: BasicBlock,
|
||||
source_info: SourceInfo,
|
||||
temp: Place<'tcx>,
|
||||
constant: Constant<'tcx>,
|
||||
constant: ConstOperand<'tcx>,
|
||||
) {
|
||||
self.push_assign(
|
||||
block,
|
||||
@ -70,10 +70,10 @@ impl<'tcx> CFG<'tcx> {
|
||||
block,
|
||||
source_info,
|
||||
place,
|
||||
Rvalue::Use(Operand::Constant(Box::new(Constant {
|
||||
Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
|
||||
span: source_info.span,
|
||||
user_ty: None,
|
||||
literal: ConstantKind::zero_sized(tcx.types.unit),
|
||||
const_: Const::zero_sized(tcx.types.unit),
|
||||
}))),
|
||||
);
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
||||
expected: "constant pattern".to_string(),
|
||||
});
|
||||
};
|
||||
values.push(value.eval_bits(self.tcx, self.param_env, arm.pattern.ty));
|
||||
values.push(value.eval_bits(self.tcx, self.param_env));
|
||||
targets.push(self.parse_block(arm.body)?);
|
||||
}
|
||||
|
||||
@ -283,12 +283,12 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
||||
ExprKind::StaticRef { alloc_id, ty, .. } => {
|
||||
let const_val =
|
||||
ConstValue::Scalar(Scalar::from_pointer((*alloc_id).into(), &self.tcx));
|
||||
let literal = ConstantKind::Val(const_val, *ty);
|
||||
let const_ = Const::Val(const_val, *ty);
|
||||
|
||||
Ok(Operand::Constant(Box::new(Constant {
|
||||
Ok(Operand::Constant(Box::new(ConstOperand {
|
||||
span: expr.span,
|
||||
user_ty: None,
|
||||
literal
|
||||
const_
|
||||
})))
|
||||
},
|
||||
)
|
||||
@ -301,7 +301,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
||||
| ExprKind::NonHirLiteral { .. }
|
||||
| ExprKind::ConstBlock { .. } => Ok({
|
||||
let value = as_constant_inner(expr, |_| None, self.tcx);
|
||||
value.literal.eval_bits(self.tcx, self.param_env, value.ty())
|
||||
value.const_.eval_bits(self.tcx, self.param_env)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ use rustc_target::abi::Size;
|
||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
/// Compile `expr`, yielding a compile-time constant. Assumes that
|
||||
/// `expr` is a valid compile-time constant!
|
||||
pub(crate) fn as_constant(&mut self, expr: &Expr<'tcx>) -> Constant<'tcx> {
|
||||
pub(crate) fn as_constant(&mut self, expr: &Expr<'tcx>) -> ConstOperand<'tcx> {
|
||||
let this = self;
|
||||
let tcx = this.tcx;
|
||||
let Expr { ty, temp_lifetime: _, span, ref kind } = *expr;
|
||||
@ -42,62 +42,62 @@ pub fn as_constant_inner<'tcx>(
|
||||
expr: &Expr<'tcx>,
|
||||
push_cuta: impl FnMut(&Box<CanonicalUserType<'tcx>>) -> Option<UserTypeAnnotationIndex>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
) -> Constant<'tcx> {
|
||||
) -> ConstOperand<'tcx> {
|
||||
let Expr { ty, temp_lifetime: _, span, ref kind } = *expr;
|
||||
match *kind {
|
||||
ExprKind::Literal { lit, neg } => {
|
||||
let literal =
|
||||
match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) {
|
||||
Ok(c) => c,
|
||||
Err(LitToConstError::Reported(guar)) => {
|
||||
ConstantKind::Ty(ty::Const::new_error(tcx, guar, ty))
|
||||
}
|
||||
Err(LitToConstError::TypeError) => {
|
||||
bug!("encountered type error in `lit_to_mir_constant`")
|
||||
}
|
||||
};
|
||||
let const_ = match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg })
|
||||
{
|
||||
Ok(c) => c,
|
||||
Err(LitToConstError::Reported(guar)) => {
|
||||
Const::Ty(ty::Const::new_error(tcx, guar, ty))
|
||||
}
|
||||
Err(LitToConstError::TypeError) => {
|
||||
bug!("encountered type error in `lit_to_mir_constant`")
|
||||
}
|
||||
};
|
||||
|
||||
Constant { span, user_ty: None, literal }
|
||||
ConstOperand { span, user_ty: None, const_ }
|
||||
}
|
||||
ExprKind::NonHirLiteral { lit, ref user_ty } => {
|
||||
let user_ty = user_ty.as_ref().and_then(push_cuta);
|
||||
|
||||
let literal = ConstantKind::Val(ConstValue::Scalar(Scalar::Int(lit)), ty);
|
||||
let const_ = Const::Val(ConstValue::Scalar(Scalar::Int(lit)), ty);
|
||||
|
||||
Constant { span, user_ty, literal }
|
||||
ConstOperand { span, user_ty, const_ }
|
||||
}
|
||||
ExprKind::ZstLiteral { ref user_ty } => {
|
||||
let user_ty = user_ty.as_ref().and_then(push_cuta);
|
||||
|
||||
let literal = ConstantKind::Val(ConstValue::ZeroSized, ty);
|
||||
let const_ = Const::Val(ConstValue::ZeroSized, ty);
|
||||
|
||||
Constant { span, user_ty, literal }
|
||||
ConstOperand { span, user_ty, const_ }
|
||||
}
|
||||
ExprKind::NamedConst { def_id, args, ref user_ty } => {
|
||||
let user_ty = user_ty.as_ref().and_then(push_cuta);
|
||||
|
||||
let uneval = mir::UnevaluatedConst::new(def_id, args);
|
||||
let literal = ConstantKind::Unevaluated(uneval, ty);
|
||||
let const_ = Const::Unevaluated(uneval, ty);
|
||||
|
||||
Constant { user_ty, span, literal }
|
||||
ConstOperand { user_ty, span, const_ }
|
||||
}
|
||||
ExprKind::ConstParam { param, def_id: _ } => {
|
||||
let const_param = ty::Const::new_param(tcx, param, expr.ty);
|
||||
let literal = ConstantKind::Ty(const_param);
|
||||
let const_ = Const::Ty(const_param);
|
||||
|
||||
Constant { user_ty: None, span, literal }
|
||||
ConstOperand { user_ty: None, span, const_ }
|
||||
}
|
||||
ExprKind::ConstBlock { did: def_id, args } => {
|
||||
let uneval = mir::UnevaluatedConst::new(def_id, args);
|
||||
let literal = ConstantKind::Unevaluated(uneval, ty);
|
||||
let const_ = Const::Unevaluated(uneval, ty);
|
||||
|
||||
Constant { user_ty: None, span, literal }
|
||||
ConstOperand { user_ty: None, span, const_ }
|
||||
}
|
||||
ExprKind::StaticRef { alloc_id, ty, .. } => {
|
||||
let const_val = ConstValue::Scalar(Scalar::from_pointer(alloc_id.into(), &tcx));
|
||||
let literal = ConstantKind::Val(const_val, ty);
|
||||
let const_ = Const::Val(const_val, ty);
|
||||
|
||||
Constant { span, user_ty: None, literal }
|
||||
ConstOperand { span, user_ty: None, const_ }
|
||||
}
|
||||
_ => span_bug!(span, "expression is not a valid constant {:?}", kind),
|
||||
}
|
||||
@ -107,7 +107,7 @@ pub fn as_constant_inner<'tcx>(
|
||||
fn lit_to_mir_constant<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
lit_input: LitToConstInput<'tcx>,
|
||||
) -> Result<ConstantKind<'tcx>, LitToConstError> {
|
||||
) -> Result<Const<'tcx>, LitToConstError> {
|
||||
let LitToConstInput { lit, ty, neg } = lit_input;
|
||||
let trunc = |n| {
|
||||
let param_ty = ty::ParamEnv::reveal_all().and(ty);
|
||||
@ -173,5 +173,5 @@ fn lit_to_mir_constant<'tcx>(
|
||||
_ => return Err(LitToConstError::TypeError),
|
||||
};
|
||||
|
||||
Ok(ConstantKind::Val(value, ty))
|
||||
Ok(Const::Val(value, ty))
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
|
||||
let mut comparer = |range: u128, bin_op: BinOp| -> Place<'tcx> {
|
||||
let range_val =
|
||||
ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(unsigned_ty));
|
||||
Const::from_bits(this.tcx, range, ty::ParamEnv::empty().and(unsigned_ty));
|
||||
let lit_op = this.literal_operand(expr.span, range_val);
|
||||
let is_bin_op = this.temp(bool_ty, expr_span);
|
||||
this.cfg.push_assign(
|
||||
@ -485,10 +485,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
}
|
||||
ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
|
||||
block = unpack!(this.stmt_expr(block, expr, None));
|
||||
block.and(Rvalue::Use(Operand::Constant(Box::new(Constant {
|
||||
block.and(Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
|
||||
span: expr_span,
|
||||
user_ty: None,
|
||||
literal: ConstantKind::zero_sized(this.tcx.types.unit),
|
||||
const_: Const::zero_sized(this.tcx.types.unit),
|
||||
}))))
|
||||
}
|
||||
|
||||
@ -817,7 +817,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
|
||||
let param_ty = ty::ParamEnv::empty().and(ty);
|
||||
let size = self.tcx.layout_of(param_ty).unwrap().size;
|
||||
let literal = ConstantKind::from_bits(self.tcx, size.unsigned_int_max(), param_ty);
|
||||
let literal = Const::from_bits(self.tcx, size.unsigned_int_max(), param_ty);
|
||||
|
||||
self.literal_operand(span, literal)
|
||||
}
|
||||
@ -828,7 +828,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
let param_ty = ty::ParamEnv::empty().and(ty);
|
||||
let bits = self.tcx.layout_of(param_ty).unwrap().size.bits();
|
||||
let n = 1 << (bits - 1);
|
||||
let literal = ConstantKind::from_bits(self.tcx, n, param_ty);
|
||||
let literal = Const::from_bits(self.tcx, n, param_ty);
|
||||
|
||||
self.literal_operand(span, literal)
|
||||
}
|
||||
|
@ -114,10 +114,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
true_block,
|
||||
source_info,
|
||||
destination,
|
||||
Constant {
|
||||
ConstOperand {
|
||||
span: expr_span,
|
||||
user_ty: None,
|
||||
literal: ConstantKind::from_bool(this.tcx, true),
|
||||
const_: Const::from_bool(this.tcx, true),
|
||||
},
|
||||
);
|
||||
|
||||
@ -125,10 +125,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
false_block,
|
||||
source_info,
|
||||
destination,
|
||||
Constant {
|
||||
ConstOperand {
|
||||
span: expr_span,
|
||||
user_ty: None,
|
||||
literal: ConstantKind::from_bool(this.tcx, false),
|
||||
const_: Const::from_bool(this.tcx, false),
|
||||
},
|
||||
);
|
||||
|
||||
@ -186,10 +186,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
short_circuit,
|
||||
source_info,
|
||||
destination,
|
||||
Constant {
|
||||
ConstOperand {
|
||||
span: expr.span,
|
||||
user_ty: None,
|
||||
literal: ConstantKind::from_bool(this.tcx, constant),
|
||||
const_: Const::from_bool(this.tcx, constant),
|
||||
},
|
||||
);
|
||||
let rhs = unpack!(this.expr_into_dest(destination, continuation, &this.thir[rhs]));
|
||||
@ -433,12 +433,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
}
|
||||
thir::InlineAsmOperand::Const { value, span } => {
|
||||
mir::InlineAsmOperand::Const {
|
||||
value: Box::new(Constant { span, user_ty: None, literal: value }),
|
||||
value: Box::new(ConstOperand {
|
||||
span,
|
||||
user_ty: None,
|
||||
const_: value,
|
||||
}),
|
||||
}
|
||||
}
|
||||
thir::InlineAsmOperand::SymFn { value, span } => {
|
||||
mir::InlineAsmOperand::SymFn {
|
||||
value: Box::new(Constant { span, user_ty: None, literal: value }),
|
||||
value: Box::new(ConstOperand {
|
||||
span,
|
||||
user_ty: None,
|
||||
const_: value,
|
||||
}),
|
||||
}
|
||||
}
|
||||
thir::InlineAsmOperand::SymStatic { def_id } => {
|
||||
|
@ -1005,13 +1005,13 @@ enum TestKind<'tcx> {
|
||||
///
|
||||
/// For `bool` we always generate two edges, one for `true` and one for
|
||||
/// `false`.
|
||||
options: FxIndexMap<ConstantKind<'tcx>, u128>,
|
||||
options: FxIndexMap<Const<'tcx>, u128>,
|
||||
},
|
||||
|
||||
/// Test for equality with value, possibly after an unsizing coercion to
|
||||
/// `ty`,
|
||||
Eq {
|
||||
value: ConstantKind<'tcx>,
|
||||
value: Const<'tcx>,
|
||||
// Integer types are handled by `SwitchInt`, and constants with ADT
|
||||
// types are converted back into patterns, so this can only be `&str`,
|
||||
// `&[T]`, `f32` or `f64`.
|
||||
@ -1622,9 +1622,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
// may want to add cases based on the candidates that are
|
||||
// available
|
||||
match test.kind {
|
||||
TestKind::SwitchInt { switch_ty, ref mut options } => {
|
||||
TestKind::SwitchInt { switch_ty: _, ref mut options } => {
|
||||
for candidate in candidates.iter() {
|
||||
if !self.add_cases_to_switch(&match_place, candidate, switch_ty, options) {
|
||||
if !self.add_cases_to_switch(&match_place, candidate, options) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -85,8 +85,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
&mut self,
|
||||
test_place: &PlaceBuilder<'tcx>,
|
||||
candidate: &Candidate<'pat, 'tcx>,
|
||||
switch_ty: Ty<'tcx>,
|
||||
options: &mut FxIndexMap<ConstantKind<'tcx>, u128>,
|
||||
options: &mut FxIndexMap<Const<'tcx>, u128>,
|
||||
) -> bool {
|
||||
let Some(match_pair) = candidate.match_pairs.iter().find(|mp| mp.place == *test_place)
|
||||
else {
|
||||
@ -95,9 +94,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
|
||||
match match_pair.pattern.kind {
|
||||
PatKind::Constant { value } => {
|
||||
options
|
||||
.entry(value)
|
||||
.or_insert_with(|| value.eval_bits(self.tcx, self.param_env, switch_ty));
|
||||
options.entry(value).or_insert_with(|| value.eval_bits(self.tcx, self.param_env));
|
||||
true
|
||||
}
|
||||
PatKind::Variant { .. } => {
|
||||
@ -255,10 +252,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
block,
|
||||
source_info,
|
||||
TerminatorKind::Call {
|
||||
func: Operand::Constant(Box::new(Constant {
|
||||
func: Operand::Constant(Box::new(ConstOperand {
|
||||
span: test.span,
|
||||
user_ty: None,
|
||||
literal: method,
|
||||
const_: method,
|
||||
})),
|
||||
args: vec![Operand::Move(ref_string)],
|
||||
destination: ref_str,
|
||||
@ -388,7 +385,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
block: BasicBlock,
|
||||
make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
|
||||
source_info: SourceInfo,
|
||||
value: ConstantKind<'tcx>,
|
||||
value: Const<'tcx>,
|
||||
mut val: Place<'tcx>,
|
||||
mut ty: Ty<'tcx>,
|
||||
) {
|
||||
@ -485,7 +482,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
block,
|
||||
source_info,
|
||||
TerminatorKind::Call {
|
||||
func: Operand::Constant(Box::new(Constant {
|
||||
func: Operand::Constant(Box::new(ConstOperand {
|
||||
span: source_info.span,
|
||||
|
||||
// FIXME(#54571): This constant comes from user input (a
|
||||
@ -494,7 +491,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
// Need to experiment.
|
||||
user_ty: None,
|
||||
|
||||
literal: method,
|
||||
const_: method,
|
||||
})),
|
||||
args: vec![Operand::Copy(val), expect],
|
||||
destination: eq_result,
|
||||
@ -800,11 +797,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
span_bug!(match_pair.pattern.span, "simplifiable pattern found: {:?}", match_pair.pattern)
|
||||
}
|
||||
|
||||
fn const_range_contains(
|
||||
&self,
|
||||
range: &PatRange<'tcx>,
|
||||
value: ConstantKind<'tcx>,
|
||||
) -> Option<bool> {
|
||||
fn const_range_contains(&self, range: &PatRange<'tcx>, value: Const<'tcx>) -> Option<bool> {
|
||||
use std::cmp::Ordering::*;
|
||||
|
||||
// For performance, it's important to only do the second
|
||||
@ -821,7 +814,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
fn values_not_contained_in_range(
|
||||
&self,
|
||||
range: &PatRange<'tcx>,
|
||||
options: &FxIndexMap<ConstantKind<'tcx>, u128>,
|
||||
options: &FxIndexMap<Const<'tcx>, u128>,
|
||||
) -> Option<bool> {
|
||||
for &val in options.keys() {
|
||||
if self.const_range_contains(range, val)? {
|
||||
@ -866,7 +859,7 @@ fn trait_method<'tcx>(
|
||||
trait_def_id: DefId,
|
||||
method_name: Symbol,
|
||||
args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
|
||||
) -> ConstantKind<'tcx> {
|
||||
) -> Const<'tcx> {
|
||||
// The unhygienic comparison here is acceptable because this is only
|
||||
// used on known traits.
|
||||
let item = tcx
|
||||
@ -877,5 +870,5 @@ fn trait_method<'tcx>(
|
||||
|
||||
let method_ty = Ty::new_fn_def(tcx, item.def_id, args);
|
||||
|
||||
ConstantKind::zero_sized(method_ty)
|
||||
Const::zero_sized(method_ty)
|
||||
}
|
||||
|
@ -25,19 +25,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
|
||||
/// Convenience function for creating a literal operand, one
|
||||
/// without any user type annotation.
|
||||
pub(crate) fn literal_operand(
|
||||
&mut self,
|
||||
span: Span,
|
||||
literal: ConstantKind<'tcx>,
|
||||
) -> Operand<'tcx> {
|
||||
let constant = Box::new(Constant { span, user_ty: None, literal });
|
||||
pub(crate) fn literal_operand(&mut self, span: Span, const_: Const<'tcx>) -> Operand<'tcx> {
|
||||
let constant = Box::new(ConstOperand { span, user_ty: None, const_ });
|
||||
Operand::Constant(constant)
|
||||
}
|
||||
|
||||
/// Returns a zero literal operand for the appropriate type, works for
|
||||
/// bool, char and integers.
|
||||
pub(crate) fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
|
||||
let literal = ConstantKind::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty));
|
||||
let literal = Const::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty));
|
||||
|
||||
self.literal_operand(span, literal)
|
||||
}
|
||||
@ -54,10 +50,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
block,
|
||||
source_info,
|
||||
temp,
|
||||
Constant {
|
||||
ConstOperand {
|
||||
span: source_info.span,
|
||||
user_ty: None,
|
||||
literal: ConstantKind::from_usize(self.tcx, value),
|
||||
const_: Const::from_usize(self.tcx, value),
|
||||
},
|
||||
);
|
||||
temp
|
||||
|
@ -633,7 +633,7 @@ fn construct_error(tcx: TyCtxt<'_>, def: LocalDefId, err: ErrorGuaranteed) -> Bo
|
||||
_ => bug!("expected closure or generator, found {ty:?}"),
|
||||
}
|
||||
}
|
||||
hir::BodyOwnerKind::Const => 0,
|
||||
hir::BodyOwnerKind::Const { .. } => 0,
|
||||
hir::BodyOwnerKind::Static(_) => 0,
|
||||
};
|
||||
let mut cfg = CFG { basic_blocks: IndexVec::new() };
|
||||
@ -700,7 +700,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
// Constants always need overflow checks.
|
||||
check_overflow |= matches!(
|
||||
tcx.hir().body_owner_kind(def),
|
||||
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_)
|
||||
hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_)
|
||||
);
|
||||
|
||||
let lint_level = LintLevel::Explicit(hir_id);
|
||||
|
@ -647,21 +647,15 @@ impl<'tcx> Cx<'tcx> {
|
||||
out_expr: out_expr.map(|expr| self.mirror_expr(expr)),
|
||||
},
|
||||
hir::InlineAsmOperand::Const { ref anon_const } => {
|
||||
let value = mir::ConstantKind::from_anon_const(
|
||||
tcx,
|
||||
anon_const.def_id,
|
||||
self.param_env,
|
||||
);
|
||||
let value =
|
||||
mir::Const::from_anon_const(tcx, anon_const.def_id, self.param_env);
|
||||
let span = tcx.def_span(anon_const.def_id);
|
||||
|
||||
InlineAsmOperand::Const { value, span }
|
||||
}
|
||||
hir::InlineAsmOperand::SymFn { ref anon_const } => {
|
||||
let value = mir::ConstantKind::from_anon_const(
|
||||
tcx,
|
||||
anon_const.def_id,
|
||||
self.param_env,
|
||||
);
|
||||
let value =
|
||||
mir::Const::from_anon_const(tcx, anon_const.def_id, self.param_env);
|
||||
let span = tcx.def_span(anon_const.def_id);
|
||||
|
||||
InlineAsmOperand::SymFn { value, span }
|
||||
|
@ -27,7 +27,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
#[instrument(level = "debug", skip(self), ret)]
|
||||
pub(super) fn const_to_pat(
|
||||
&self,
|
||||
cv: mir::ConstantKind<'tcx>,
|
||||
cv: mir::Const<'tcx>,
|
||||
id: hir::HirId,
|
||||
span: Span,
|
||||
check_body_for_struct_match_violation: Option<DefId>,
|
||||
@ -104,7 +104,7 @@ impl<'tcx> ConstToPat<'tcx> {
|
||||
|
||||
fn to_pat(
|
||||
&mut self,
|
||||
cv: mir::ConstantKind<'tcx>,
|
||||
cv: mir::Const<'tcx>,
|
||||
check_body_for_struct_match_violation: Option<DefId>,
|
||||
) -> Box<Pat<'tcx>> {
|
||||
trace!(self.treat_byte_string_as_slice);
|
||||
@ -124,7 +124,7 @@ impl<'tcx> ConstToPat<'tcx> {
|
||||
debug!(?check_body_for_struct_match_violation, ?mir_structural_match_violation);
|
||||
|
||||
let inlined_const_as_pat = match cv {
|
||||
mir::ConstantKind::Ty(c) => match c.kind() {
|
||||
mir::Const::Ty(c) => match c.kind() {
|
||||
ty::ConstKind::Param(_)
|
||||
| ty::ConstKind::Infer(_)
|
||||
| ty::ConstKind::Bound(_, _)
|
||||
@ -144,10 +144,10 @@ impl<'tcx> ConstToPat<'tcx> {
|
||||
})
|
||||
}),
|
||||
},
|
||||
mir::ConstantKind::Unevaluated(_, _) => {
|
||||
mir::Const::Unevaluated(_, _) => {
|
||||
span_bug!(self.span, "unevaluated const in `to_pat`: {cv:?}")
|
||||
}
|
||||
mir::ConstantKind::Val(_, _) => Box::new(Pat {
|
||||
mir::Const::Val(_, _) => Box::new(Pat {
|
||||
span: self.span,
|
||||
ty: cv.ty(),
|
||||
kind: PatKind::Constant { value: cv },
|
||||
@ -385,9 +385,9 @@ impl<'tcx> ConstToPat<'tcx> {
|
||||
ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() {
|
||||
// `&str` is represented as a valtree, let's keep using this
|
||||
// optimization for now.
|
||||
ty::Str => PatKind::Constant {
|
||||
value: mir::ConstantKind::Ty(ty::Const::new_value(tcx, cv, ty)),
|
||||
},
|
||||
ty::Str => {
|
||||
PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) }
|
||||
}
|
||||
// Backwards compatibility hack: support references to non-structural types,
|
||||
// but hard error if we aren't behind a double reference. We could just use
|
||||
// the fallback code path below, but that would allow *more* of this fishy
|
||||
@ -445,9 +445,9 @@ impl<'tcx> ConstToPat<'tcx> {
|
||||
}
|
||||
}
|
||||
},
|
||||
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) => PatKind::Constant {
|
||||
value: mir::ConstantKind::Ty(ty::Const::new_value(tcx, cv, ty)),
|
||||
},
|
||||
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) => {
|
||||
PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) }
|
||||
}
|
||||
ty::FnPtr(..) | ty::RawPtr(..) => unreachable!(),
|
||||
_ => {
|
||||
self.saw_const_match_error.set(true);
|
||||
|
@ -137,16 +137,16 @@ impl IntRange {
|
||||
fn from_constant<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
value: mir::ConstantKind<'tcx>,
|
||||
value: mir::Const<'tcx>,
|
||||
) -> Option<IntRange> {
|
||||
let ty = value.ty();
|
||||
let (target_size, bias) = Self::integral_size_and_signed_bias(tcx, ty)?;
|
||||
let val = match value {
|
||||
mir::ConstantKind::Ty(c) if let ty::ConstKind::Value(valtree) = c.kind() => {
|
||||
mir::Const::Ty(c) if let ty::ConstKind::Value(valtree) = c.kind() => {
|
||||
valtree.unwrap_leaf().to_bits(target_size).ok()
|
||||
},
|
||||
// This is a more general form of the previous case.
|
||||
_ => value.try_eval_bits(tcx, param_env, ty),
|
||||
_ => value.try_eval_bits(tcx, param_env),
|
||||
}?;
|
||||
|
||||
let val = val ^ bias;
|
||||
@ -225,8 +225,8 @@ impl IntRange {
|
||||
let (lo, hi) = (lo ^ bias, hi ^ bias);
|
||||
|
||||
let env = ty::ParamEnv::empty().and(ty);
|
||||
let lo_const = mir::ConstantKind::from_bits(tcx, lo, env);
|
||||
let hi_const = mir::ConstantKind::from_bits(tcx, hi, env);
|
||||
let lo_const = mir::Const::from_bits(tcx, lo, env);
|
||||
let hi_const = mir::Const::from_bits(tcx, hi, env);
|
||||
|
||||
let kind = if lo == hi {
|
||||
PatKind::Constant { value: lo_const }
|
||||
@ -619,9 +619,9 @@ 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(mir::ConstantKind<'tcx>, mir::ConstantKind<'tcx>, RangeEnd),
|
||||
FloatRange(mir::Const<'tcx>, mir::Const<'tcx>, RangeEnd),
|
||||
/// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
|
||||
Str(mir::ConstantKind<'tcx>),
|
||||
Str(mir::Const<'tcx>),
|
||||
/// Array and slice patterns.
|
||||
Slice(Slice),
|
||||
/// Constants that must not be matched structurally. They are treated as black
|
||||
@ -1379,8 +1379,8 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
|
||||
let ty = lo.ty();
|
||||
ctor = 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()),
|
||||
lo.eval_bits(cx.tcx, cx.param_env),
|
||||
hi.eval_bits(cx.tcx, cx.param_env),
|
||||
ty,
|
||||
&end,
|
||||
) {
|
||||
|
@ -20,7 +20,7 @@ use rustc_index::Idx;
|
||||
use rustc_middle::mir::interpret::{
|
||||
ErrorHandled, GlobalId, LitToConstError, LitToConstInput, Scalar,
|
||||
};
|
||||
use rustc_middle::mir::{self, ConstantKind, UserTypeProjection};
|
||||
use rustc_middle::mir::{self, Const, UserTypeProjection};
|
||||
use rustc_middle::mir::{BorrowKind, Mutability};
|
||||
use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange};
|
||||
use rustc_middle::ty::CanonicalUserTypeAnnotation;
|
||||
@ -100,8 +100,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
fn lower_pattern_range(
|
||||
&mut self,
|
||||
ty: Ty<'tcx>,
|
||||
lo: mir::ConstantKind<'tcx>,
|
||||
hi: mir::ConstantKind<'tcx>,
|
||||
lo: mir::Const<'tcx>,
|
||||
hi: mir::Const<'tcx>,
|
||||
end: RangeEnd,
|
||||
span: Span,
|
||||
lo_expr: Option<&hir::Expr<'tcx>>,
|
||||
@ -131,7 +131,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr
|
||||
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
|
||||
{
|
||||
if lo.eval_bits(self.tcx, self.param_env, ty) != val {
|
||||
if lo.eval_bits(self.tcx, self.param_env) != val {
|
||||
lower_overflow = true;
|
||||
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
|
||||
}
|
||||
@ -139,7 +139,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr
|
||||
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
|
||||
{
|
||||
if hi.eval_bits(self.tcx, self.param_env, ty) != val {
|
||||
if hi.eval_bits(self.tcx, self.param_env) != val {
|
||||
higher_overflow = true;
|
||||
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
|
||||
}
|
||||
@ -162,7 +162,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr
|
||||
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
|
||||
{
|
||||
if lo.eval_bits(self.tcx, self.param_env, ty) != val {
|
||||
if lo.eval_bits(self.tcx, self.param_env) != val {
|
||||
lower_overflow = true;
|
||||
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
|
||||
}
|
||||
@ -170,7 +170,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr
|
||||
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
|
||||
{
|
||||
if hi.eval_bits(self.tcx, self.param_env, ty) != val {
|
||||
if hi.eval_bits(self.tcx, self.param_env) != val {
|
||||
higher_overflow = true;
|
||||
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
|
||||
}
|
||||
@ -191,18 +191,18 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
ty: Ty<'tcx>,
|
||||
lo: Option<&PatKind<'tcx>>,
|
||||
hi: Option<&PatKind<'tcx>>,
|
||||
) -> Option<(mir::ConstantKind<'tcx>, mir::ConstantKind<'tcx>)> {
|
||||
) -> Option<(mir::Const<'tcx>, mir::Const<'tcx>)> {
|
||||
match (lo, hi) {
|
||||
(Some(PatKind::Constant { value: lo }), Some(PatKind::Constant { value: hi })) => {
|
||||
Some((*lo, *hi))
|
||||
}
|
||||
(Some(PatKind::Constant { value: lo }), None) => {
|
||||
let hi = ty.numeric_max_val(self.tcx)?;
|
||||
Some((*lo, mir::ConstantKind::from_ty_const(hi, self.tcx)))
|
||||
Some((*lo, mir::Const::from_ty_const(hi, self.tcx)))
|
||||
}
|
||||
(None, Some(PatKind::Constant { value: hi })) => {
|
||||
let lo = ty.numeric_min_val(self.tcx)?;
|
||||
Some((mir::ConstantKind::from_ty_const(lo, self.tcx), *hi))
|
||||
Some((mir::Const::from_ty_const(lo, self.tcx), *hi))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
@ -525,8 +525,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
.tcx
|
||||
.const_eval_global_id_for_typeck(param_env_reveal_all, cid, Some(span))
|
||||
.map(|val| match val {
|
||||
Some(valtree) => mir::ConstantKind::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
|
||||
None => mir::ConstantKind::Val(
|
||||
Some(valtree) => mir::Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
|
||||
None => mir::Const::Val(
|
||||
self.tcx
|
||||
.const_eval_global_id(param_env_reveal_all, cid, Some(span))
|
||||
.expect("const_eval_global_id_for_typeck should have already failed"),
|
||||
@ -608,7 +608,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
};
|
||||
if let Some(lit_input) = lit_input {
|
||||
match tcx.at(expr.span).lit_to_const(lit_input) {
|
||||
Ok(c) => return self.const_to_pat(ConstantKind::Ty(c), id, span, None).kind,
|
||||
Ok(c) => return self.const_to_pat(Const::Ty(c), id, span, None).kind,
|
||||
// If an error occurred, ignore that it's a literal
|
||||
// and leave reporting the error up to const eval of
|
||||
// the unevaluated constant below.
|
||||
@ -632,7 +632,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span))
|
||||
{
|
||||
self.const_to_pat(
|
||||
ConstantKind::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
|
||||
Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
|
||||
id,
|
||||
span,
|
||||
None,
|
||||
@ -641,7 +641,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
} else {
|
||||
// If that fails, convert it to an opaque constant pattern.
|
||||
match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) {
|
||||
Ok(val) => self.const_to_pat(mir::ConstantKind::Val(val, ty), id, span, None).kind,
|
||||
Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span, None).kind,
|
||||
Err(ErrorHandled::TooGeneric(_)) => {
|
||||
// If we land here it means the const can't be evaluated because it's `TooGeneric`.
|
||||
self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
|
||||
@ -678,7 +678,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||
LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
|
||||
match self.tcx.at(expr.span).lit_to_const(lit_input) {
|
||||
Ok(constant) => {
|
||||
self.const_to_pat(ConstantKind::Ty(constant), expr.hir_id, lit.span, None).kind
|
||||
self.const_to_pat(Const::Ty(constant), expr.hir_id, lit.span, None).kind
|
||||
}
|
||||
Err(LitToConstError::Reported(_)) => PatKind::Wild,
|
||||
Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
|
||||
@ -838,8 +838,8 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> {
|
||||
#[instrument(skip(tcx), level = "debug")]
|
||||
pub(crate) fn compare_const_vals<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
a: mir::ConstantKind<'tcx>,
|
||||
b: mir::ConstantKind<'tcx>,
|
||||
a: mir::Const<'tcx>,
|
||||
b: mir::Const<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> Option<Ordering> {
|
||||
assert_eq!(a.ty(), b.ty());
|
||||
@ -855,18 +855,18 @@ pub(crate) fn compare_const_vals<'tcx>(
|
||||
ty::Float(_) | ty::Int(_) => {} // require special handling, see below
|
||||
_ => match (a, b) {
|
||||
(
|
||||
mir::ConstantKind::Val(mir::ConstValue::Scalar(Scalar::Int(a)), _a_ty),
|
||||
mir::ConstantKind::Val(mir::ConstValue::Scalar(Scalar::Int(b)), _b_ty),
|
||||
mir::Const::Val(mir::ConstValue::Scalar(Scalar::Int(a)), _a_ty),
|
||||
mir::Const::Val(mir::ConstValue::Scalar(Scalar::Int(b)), _b_ty),
|
||||
) => return Some(a.cmp(&b)),
|
||||
(mir::ConstantKind::Ty(a), mir::ConstantKind::Ty(b)) => {
|
||||
(mir::Const::Ty(a), mir::Const::Ty(b)) => {
|
||||
return Some(a.kind().cmp(&b.kind()));
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
}
|
||||
|
||||
let a = a.eval_bits(tcx, param_env, ty);
|
||||
let b = b.eval_bits(tcx, param_env, ty);
|
||||
let a = a.eval_bits(tcx, param_env);
|
||||
let b = b.eval_bits(tcx, param_env);
|
||||
|
||||
use rustc_apfloat::Float;
|
||||
match *ty.kind() {
|
||||
|
@ -973,10 +973,10 @@ where
|
||||
}
|
||||
|
||||
fn constant_usize(&self, val: u16) -> Operand<'tcx> {
|
||||
Operand::Constant(Box::new(Constant {
|
||||
Operand::Constant(Box::new(ConstOperand {
|
||||
span: self.source_info.span,
|
||||
user_ty: None,
|
||||
literal: ConstantKind::from_usize(self.tcx(), val.into()),
|
||||
const_: Const::from_usize(self.tcx(), val.into()),
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -190,7 +190,7 @@ impl PeekCall {
|
||||
if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } =
|
||||
&terminator.kind
|
||||
{
|
||||
if let ty::FnDef(def_id, fn_args) = *func.literal.ty().kind() {
|
||||
if let ty::FnDef(def_id, fn_args) = *func.const_.ty().kind() {
|
||||
let name = tcx.item_name(def_id);
|
||||
if !tcx.is_intrinsic(def_id) || name != sym::rustc_peek {
|
||||
return None;
|
||||
|
@ -225,7 +225,7 @@ pub trait ValueAnalysis<'tcx> {
|
||||
|
||||
fn handle_constant(
|
||||
&self,
|
||||
constant: &Constant<'tcx>,
|
||||
constant: &ConstOperand<'tcx>,
|
||||
state: &mut State<Self::Value>,
|
||||
) -> Self::Value {
|
||||
self.super_constant(constant, state)
|
||||
@ -233,7 +233,7 @@ pub trait ValueAnalysis<'tcx> {
|
||||
|
||||
fn super_constant(
|
||||
&self,
|
||||
_constant: &Constant<'tcx>,
|
||||
_constant: &ConstOperand<'tcx>,
|
||||
_state: &mut State<Self::Value>,
|
||||
) -> Self::Value {
|
||||
Self::Value::TOP
|
||||
|
@ -181,13 +181,10 @@ fn insert_alignment_check<'tcx>(
|
||||
// Subtract 1 from the alignment to get the alignment mask
|
||||
let alignment_mask =
|
||||
local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
|
||||
let one = Operand::Constant(Box::new(Constant {
|
||||
let one = Operand::Constant(Box::new(ConstOperand {
|
||||
span: source_info.span,
|
||||
user_ty: None,
|
||||
literal: ConstantKind::Val(
|
||||
ConstValue::Scalar(Scalar::from_target_usize(1, &tcx)),
|
||||
tcx.types.usize,
|
||||
),
|
||||
const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(1, &tcx)), tcx.types.usize),
|
||||
}));
|
||||
block_data.statements.push(Statement {
|
||||
source_info,
|
||||
@ -213,13 +210,10 @@ fn insert_alignment_check<'tcx>(
|
||||
|
||||
// Check if the alignment bits are all zero
|
||||
let is_ok = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
|
||||
let zero = Operand::Constant(Box::new(Constant {
|
||||
let zero = Operand::Constant(Box::new(ConstOperand {
|
||||
span: source_info.span,
|
||||
user_ty: None,
|
||||
literal: ConstantKind::Val(
|
||||
ConstValue::Scalar(Scalar::from_target_usize(0, &tcx)),
|
||||
tcx.types.usize,
|
||||
),
|
||||
const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(0, &tcx)), tcx.types.usize),
|
||||
}));
|
||||
block_data.statements.push(Statement {
|
||||
source_info,
|
||||
|
@ -142,9 +142,9 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
|
||||
|
||||
fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
|
||||
if let Operand::Constant(constant) = op {
|
||||
let maybe_uneval = match constant.literal {
|
||||
ConstantKind::Val(..) | ConstantKind::Ty(_) => None,
|
||||
ConstantKind::Unevaluated(uv, _) => Some(uv),
|
||||
let maybe_uneval = match constant.const_ {
|
||||
Const::Val(..) | Const::Ty(_) => None,
|
||||
Const::Unevaluated(uv, _) => Some(uv),
|
||||
};
|
||||
|
||||
if let Some(uv) = maybe_uneval {
|
||||
|
@ -4,7 +4,7 @@
|
||||
use rustc_middle::{
|
||||
mir::{
|
||||
visit::{PlaceContext, Visitor},
|
||||
Body, Constant, Local, Location, Operand, Rvalue, StatementKind, VarDebugInfoContents,
|
||||
Body, ConstOperand, Local, Location, Operand, Rvalue, StatementKind, VarDebugInfoContents,
|
||||
},
|
||||
ty::TyCtxt,
|
||||
};
|
||||
@ -45,7 +45,7 @@ struct LocalUseVisitor {
|
||||
local_assignment_locations: IndexVec<Local, Option<Location>>,
|
||||
}
|
||||
|
||||
fn find_optimization_opportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, Constant<'tcx>)> {
|
||||
fn find_optimization_opportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, ConstOperand<'tcx>)> {
|
||||
let mut visitor = LocalUseVisitor {
|
||||
local_mutating_uses: IndexVec::from_elem(0, &body.local_decls),
|
||||
local_assignment_locations: IndexVec::from_elem(None, &body.local_decls),
|
||||
|
@ -96,10 +96,10 @@ impl<'tcx> Visitor<'tcx> for ConstGotoOptimizationFinder<'_, 'tcx> {
|
||||
let (discr, targets) = target_bb_terminator.kind.as_switch()?;
|
||||
if discr.place() == Some(*place) {
|
||||
let switch_ty = place.ty(self.body.local_decls(), self.tcx).ty;
|
||||
debug_assert_eq!(switch_ty, _const.ty());
|
||||
// We now know that the Switch matches on the const place, and it is statementless
|
||||
// Now find which value in the Switch matches the const value.
|
||||
let const_value =
|
||||
_const.literal.try_eval_bits(self.tcx, self.param_env, switch_ty)?;
|
||||
let const_value = _const.const_.try_eval_bits(self.tcx, self.param_env)?;
|
||||
let target_to_use_in_goto = targets.target_for_value(const_value);
|
||||
self.optimizations.push(OptimizationToApply {
|
||||
bb_with_goto: location.block,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user