Auto merge of #3074 - rust-lang:rustup-2023-09-22, r=RalfJung

Automatic sync from rustc
This commit is contained in:
bors 2023-09-22 08:36:18 +00:00
commit ce33ca0a1e
255 changed files with 3180 additions and 2195 deletions

View File

@ -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,
}
}

View File

@ -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() {

View File

@ -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

View File

@ -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);
}
}

View File

@ -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 {

View File

@ -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 =

View File

@ -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)

View File

@ -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(),

View File

@ -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,

View File

@ -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))
}
}

View File

@ -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();

View File

@ -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 => {

View File

@ -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(),

View File

@ -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

View File

@ -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");
}

View File

@ -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, .. })) => {

View File

@ -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.

View File

@ -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>> {

View File

@ -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()
})
}

View File

@ -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

View File

@ -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

View File

@ -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)
}
}

View File

@ -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,
);

View File

@ -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)?;
}

View File

@ -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.

View File

@ -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()

View File

@ -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())
}

View File

@ -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;

View File

@ -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;

View File

@ -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",
}))
}
}

View File

@ -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

View File

@ -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`

View File

@ -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,
);
}
_ => {

View File

@ -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,
);
}
}

View File

@ -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(),
}
}
}

View File

@ -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(

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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")

View File

@ -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,
);
}

View File

@ -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]

View File

@ -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) {

View File

@ -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);
}

View File

@ -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) {

View File

@ -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) }
}

View File

@ -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

View File

@ -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]

View File

@ -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",

View File

@ -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 _));
}

View File

@ -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)

View File

@ -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> {

View File

@ -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);
}
}
_ => {}

View File

@ -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);
}

View File

@ -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>>,

View File

@ -205,9 +205,9 @@ fixed_size_enum! {
}
fixed_size_enum! {
hir::IsAsync {
( NotAsync )
( Async )
ty::Asyncness {
( Yes )
( No )
}
}

View File

@ -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:

View File

@ -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()]
}
}

View File

@ -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,

View File

@ -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(())
}

View File

@ -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

View File

@ -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> {

View File

@ -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));
}
}

View File

@ -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

View File

@ -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>,
}
///////////////////////////////////////////////////////////////////////////

View File

@ -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(),
}
}
}

View File

@ -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)),
}
}

View File

@ -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,

View File

@ -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 {

View File

@ -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>)

View File

@ -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,

View File

@ -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,
}

View File

@ -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.
}

View File

@ -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,

View File

@ -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]

View File

@ -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).

View File

@ -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,

View File

@ -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,

View File

@ -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)
{

View File

@ -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).

View File

@ -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),
}))),
);
}

View File

@ -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)
}),
)
}

View File

@ -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))
}

View File

@ -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)
}

View File

@ -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 } => {

View File

@ -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;
}
}

View File

@ -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)
}

View File

@ -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

View File

@ -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);

View File

@ -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 }

View File

@ -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);

View File

@ -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,
) {

View File

@ -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() {

View File

@ -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()),
}))
}

View File

@ -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;

View File

@ -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

View File

@ -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,

View File

@ -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 {

View File

@ -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),

View File

@ -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