Auto merge of #67133 - oli-obk:it_must_be_a_sign, r=eddyb
Deduplicate pretty printing of constants r? @eddyb for the pretty printing logic cc @RalfJung
This commit is contained in:
commit
dd67187965
15 changed files with 396 additions and 206 deletions
|
@ -2562,15 +2562,15 @@ impl<'tcx> Debug for Constant<'tcx> {
|
||||||
|
|
||||||
impl<'tcx> Display for Constant<'tcx> {
|
impl<'tcx> Display for Constant<'tcx> {
|
||||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
use crate::ty::print::PrettyPrinter;
|
||||||
write!(fmt, "const ")?;
|
write!(fmt, "const ")?;
|
||||||
// FIXME make the default pretty printing of raw pointers more detailed. Here we output the
|
ty::tls::with(|tcx| {
|
||||||
// debug representation of raw pointers, so that the raw pointers in the mir dump output are
|
let literal = tcx.lift(&self.literal).unwrap();
|
||||||
// detailed and just not '{pointer}'.
|
let mut cx = FmtPrinter::new(tcx, fmt, Namespace::ValueNS);
|
||||||
if let ty::RawPtr(_) = self.literal.ty.kind {
|
cx.print_alloc_ids = true;
|
||||||
write!(fmt, "{:?} : {}", self.literal.val, self.literal.ty)
|
cx.pretty_print_const(literal, true)?;
|
||||||
} else {
|
Ok(())
|
||||||
write!(fmt, "{}", self.literal)
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::hir::map::{DefPathData, DisambiguatedDefPathData};
|
use crate::hir::map::{DefPathData, DisambiguatedDefPathData};
|
||||||
use crate::middle::cstore::{ExternCrate, ExternCrateSource};
|
use crate::middle::cstore::{ExternCrate, ExternCrateSource};
|
||||||
use crate::middle::region;
|
use crate::middle::region;
|
||||||
use crate::mir::interpret::{sign_extend, truncate, ConstValue, Scalar};
|
use crate::mir::interpret::{sign_extend, truncate, AllocId, ConstValue, Pointer, Scalar};
|
||||||
use crate::ty::layout::{Integer, IntegerExt, Size};
|
use crate::ty::layout::{Integer, IntegerExt, Size};
|
||||||
use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
|
use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
|
||||||
use crate::ty::{self, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable};
|
use crate::ty::{self, DefIdTree, ParamConst, Ty, TyCtxt, TypeFoldable};
|
||||||
|
@ -17,6 +17,7 @@ use rustc_span::symbol::{kw, Symbol};
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
use std::char;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::fmt::{self, Write as _};
|
use std::fmt::{self, Write as _};
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
@ -210,6 +211,21 @@ pub trait PrettyPrinter<'tcx>:
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Prints `{f: t}` or `{f as t}` depending on the `cast` argument
|
||||||
|
fn typed_value(
|
||||||
|
mut self,
|
||||||
|
f: impl FnOnce(Self) -> Result<Self, Self::Error>,
|
||||||
|
t: impl FnOnce(Self) -> Result<Self, Self::Error>,
|
||||||
|
conversion: &str,
|
||||||
|
) -> Result<Self::Const, Self::Error> {
|
||||||
|
self.write_str("{")?;
|
||||||
|
self = f(self)?;
|
||||||
|
self.write_str(conversion)?;
|
||||||
|
self = t(self)?;
|
||||||
|
self.write_str("}")?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
/// Prints `<...>` around what `f` prints.
|
/// Prints `<...>` around what `f` prints.
|
||||||
fn generic_delimiters(
|
fn generic_delimiters(
|
||||||
self,
|
self,
|
||||||
|
@ -517,14 +533,7 @@ pub trait PrettyPrinter<'tcx>:
|
||||||
ty::Error => p!(write("[type error]")),
|
ty::Error => p!(write("[type error]")),
|
||||||
ty::Param(ref param_ty) => p!(write("{}", param_ty)),
|
ty::Param(ref param_ty) => p!(write("{}", param_ty)),
|
||||||
ty::Bound(debruijn, bound_ty) => match bound_ty.kind {
|
ty::Bound(debruijn, bound_ty) => match bound_ty.kind {
|
||||||
ty::BoundTyKind::Anon => {
|
ty::BoundTyKind::Anon => self.pretty_print_bound_var(debruijn, bound_ty.var)?,
|
||||||
if debruijn == ty::INNERMOST {
|
|
||||||
p!(write("^{}", bound_ty.var.index()))
|
|
||||||
} else {
|
|
||||||
p!(write("^{}_{}", debruijn.index(), bound_ty.var.index()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ty::BoundTyKind::Param(p) => p!(write("{}", p)),
|
ty::BoundTyKind::Param(p) => p!(write("{}", p)),
|
||||||
},
|
},
|
||||||
ty::Adt(def, substs) => {
|
ty::Adt(def, substs) => {
|
||||||
|
@ -689,7 +698,7 @@ pub trait PrettyPrinter<'tcx>:
|
||||||
// array length anon const, rustc will (with debug assertions) print the
|
// array length anon const, rustc will (with debug assertions) print the
|
||||||
// constant's path. Which will end up here again.
|
// constant's path. Which will end up here again.
|
||||||
p!(write("_"));
|
p!(write("_"));
|
||||||
} else if let Some(n) = sz.try_eval_usize(self.tcx(), ty::ParamEnv::empty()) {
|
} else if let Some(n) = sz.val.try_to_bits(self.tcx().data_layout.pointer_size) {
|
||||||
p!(write("{}", n));
|
p!(write("{}", n));
|
||||||
} else {
|
} else {
|
||||||
p!(write("_"));
|
p!(write("_"));
|
||||||
|
@ -702,6 +711,18 @@ pub trait PrettyPrinter<'tcx>:
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pretty_print_bound_var(
|
||||||
|
&mut self,
|
||||||
|
debruijn: ty::DebruijnIndex,
|
||||||
|
var: ty::BoundVar,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
if debruijn == ty::INNERMOST {
|
||||||
|
write!(self, "^{}", var.index())
|
||||||
|
} else {
|
||||||
|
write!(self, "^{}_{}", debruijn.index(), var.index())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn infer_ty_name(&self, _: ty::TyVid) -> Option<String> {
|
fn infer_ty_name(&self, _: ty::TyVid) -> Option<String> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -842,16 +863,23 @@ pub trait PrettyPrinter<'tcx>:
|
||||||
|
|
||||||
macro_rules! print_underscore {
|
macro_rules! print_underscore {
|
||||||
() => {{
|
() => {{
|
||||||
p!(write("_"));
|
|
||||||
if print_ty {
|
if print_ty {
|
||||||
p!(write(": "), print(ct.ty));
|
self = self.typed_value(
|
||||||
|
|mut this| {
|
||||||
|
write!(this, "_")?;
|
||||||
|
Ok(this)
|
||||||
|
},
|
||||||
|
|this| this.print_type(ct.ty),
|
||||||
|
": ",
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
write!(self, "_")?;
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
match (ct.val, &ct.ty.kind) {
|
match ct.val {
|
||||||
(_, ty::FnDef(did, substs)) => p!(print_value_path(*did, substs)),
|
ty::ConstKind::Unevaluated(did, substs, promoted) => {
|
||||||
(ty::ConstKind::Unevaluated(did, substs, promoted), _) => {
|
|
||||||
if let Some(promoted) = promoted {
|
if let Some(promoted) = promoted {
|
||||||
p!(print_value_path(did, substs));
|
p!(print_value_path(did, substs));
|
||||||
p!(write("::{:?}", promoted));
|
p!(write("::{:?}", promoted));
|
||||||
|
@ -876,23 +904,203 @@ pub trait PrettyPrinter<'tcx>:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(ty::ConstKind::Infer(..), _) => print_underscore!(),
|
ty::ConstKind::Infer(..) => print_underscore!(),
|
||||||
(ty::ConstKind::Param(ParamConst { name, .. }), _) => p!(write("{}", name)),
|
ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)),
|
||||||
(ty::ConstKind::Value(value), _) => {
|
ty::ConstKind::Value(value) => {
|
||||||
return self.pretty_print_const_value(value, ct.ty, print_ty);
|
return self.pretty_print_const_value(value, ct.ty, print_ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
ty::ConstKind::Bound(debruijn, bound_var) => {
|
||||||
// fallback
|
self.pretty_print_bound_var(debruijn, bound_var)?
|
||||||
p!(write("{:?}", ct.val));
|
|
||||||
if print_ty {
|
|
||||||
p!(write(": "), print(ct.ty));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
ty::ConstKind::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)),
|
||||||
};
|
};
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pretty_print_const_scalar(
|
||||||
|
mut self,
|
||||||
|
scalar: Scalar,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
print_ty: bool,
|
||||||
|
) -> Result<Self::Const, Self::Error> {
|
||||||
|
define_scoped_cx!(self);
|
||||||
|
|
||||||
|
match (scalar, &ty.kind) {
|
||||||
|
// Byte strings (&[u8; N])
|
||||||
|
(
|
||||||
|
Scalar::Ptr(ptr),
|
||||||
|
ty::Ref(
|
||||||
|
_,
|
||||||
|
ty::TyS {
|
||||||
|
kind:
|
||||||
|
ty::Array(
|
||||||
|
ty::TyS { kind: ty::Uint(ast::UintTy::U8), .. },
|
||||||
|
ty::Const {
|
||||||
|
val:
|
||||||
|
ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw {
|
||||||
|
data,
|
||||||
|
..
|
||||||
|
})),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
_,
|
||||||
|
),
|
||||||
|
) => {
|
||||||
|
let byte_str = self
|
||||||
|
.tcx()
|
||||||
|
.alloc_map
|
||||||
|
.lock()
|
||||||
|
.unwrap_memory(ptr.alloc_id)
|
||||||
|
.get_bytes(&self.tcx(), ptr, Size::from_bytes(*data as u64))
|
||||||
|
.unwrap();
|
||||||
|
p!(pretty_print_byte_str(byte_str));
|
||||||
|
}
|
||||||
|
// Bool
|
||||||
|
(Scalar::Raw { data: 0, .. }, ty::Bool) => p!(write("false")),
|
||||||
|
(Scalar::Raw { data: 1, .. }, ty::Bool) => p!(write("true")),
|
||||||
|
// Float
|
||||||
|
(Scalar::Raw { data, .. }, ty::Float(ast::FloatTy::F32)) => {
|
||||||
|
p!(write("{}f32", Single::from_bits(data)))
|
||||||
|
}
|
||||||
|
(Scalar::Raw { data, .. }, ty::Float(ast::FloatTy::F64)) => {
|
||||||
|
p!(write("{}f64", Double::from_bits(data)))
|
||||||
|
}
|
||||||
|
// Int
|
||||||
|
(Scalar::Raw { data, .. }, ty::Uint(ui)) => {
|
||||||
|
let bit_size = Integer::from_attr(&self.tcx(), UnsignedInt(*ui)).size();
|
||||||
|
let max = truncate(u128::MAX, bit_size);
|
||||||
|
|
||||||
|
let ui_str = ui.name_str();
|
||||||
|
if data == max {
|
||||||
|
p!(write("std::{}::MAX", ui_str))
|
||||||
|
} else {
|
||||||
|
if print_ty { p!(write("{}{}", data, ui_str)) } else { p!(write("{}", data)) }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
(Scalar::Raw { data, .. }, ty::Int(i)) => {
|
||||||
|
let size = Integer::from_attr(&self.tcx(), SignedInt(*i)).size();
|
||||||
|
let bit_size = size.bits() as u128;
|
||||||
|
let min = 1u128 << (bit_size - 1);
|
||||||
|
let max = min - 1;
|
||||||
|
|
||||||
|
let i_str = i.name_str();
|
||||||
|
match data {
|
||||||
|
d if d == min => p!(write("std::{}::MIN", i_str)),
|
||||||
|
d if d == max => p!(write("std::{}::MAX", i_str)),
|
||||||
|
_ => {
|
||||||
|
let data = sign_extend(data, size) as i128;
|
||||||
|
if print_ty {
|
||||||
|
p!(write("{}{}", data, i_str))
|
||||||
|
} else {
|
||||||
|
p!(write("{}", data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Char
|
||||||
|
(Scalar::Raw { data, .. }, ty::Char) if char::from_u32(data as u32).is_some() => {
|
||||||
|
p!(write("{:?}", char::from_u32(data as u32).unwrap()))
|
||||||
|
}
|
||||||
|
// Raw pointers
|
||||||
|
(Scalar::Raw { data, .. }, ty::RawPtr(_)) => {
|
||||||
|
self = self.typed_value(
|
||||||
|
|mut this| {
|
||||||
|
write!(this, "0x{:x}", data)?;
|
||||||
|
Ok(this)
|
||||||
|
},
|
||||||
|
|this| this.print_type(ty),
|
||||||
|
" as ",
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
(Scalar::Ptr(ptr), ty::FnPtr(_)) => {
|
||||||
|
let instance = {
|
||||||
|
let alloc_map = self.tcx().alloc_map.lock();
|
||||||
|
alloc_map.unwrap_fn(ptr.alloc_id)
|
||||||
|
};
|
||||||
|
self = self.typed_value(
|
||||||
|
|this| this.print_value_path(instance.def_id(), instance.substs),
|
||||||
|
|this| this.print_type(ty),
|
||||||
|
" as ",
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
// For function type zsts just printing the path is enough
|
||||||
|
(Scalar::Raw { size: 0, .. }, ty::FnDef(d, s)) => p!(print_value_path(*d, s)),
|
||||||
|
// Empty tuples are frequently occurring, so don't print the fallback.
|
||||||
|
(Scalar::Raw { size: 0, .. }, ty::Tuple(ts)) if ts.is_empty() => p!(write("()")),
|
||||||
|
// Zero element arrays have a trivial representation.
|
||||||
|
(
|
||||||
|
Scalar::Raw { size: 0, .. },
|
||||||
|
ty::Array(
|
||||||
|
_,
|
||||||
|
ty::Const {
|
||||||
|
val: ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data: 0, .. })),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
),
|
||||||
|
) => p!(write("[]")),
|
||||||
|
// Nontrivial types with scalar bit representation
|
||||||
|
(Scalar::Raw { data, size }, _) => {
|
||||||
|
let print = |mut this: Self| {
|
||||||
|
if size == 0 {
|
||||||
|
write!(this, "transmute(())")?;
|
||||||
|
} else {
|
||||||
|
write!(this, "transmute(0x{:01$x})", data, size as usize * 2)?;
|
||||||
|
}
|
||||||
|
Ok(this)
|
||||||
|
};
|
||||||
|
self = if print_ty {
|
||||||
|
self.typed_value(print, |this| this.print_type(ty), ": ")?
|
||||||
|
} else {
|
||||||
|
print(self)?
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Any pointer values not covered by a branch above
|
||||||
|
(Scalar::Ptr(p), _) => {
|
||||||
|
self = self.pretty_print_const_pointer(p, ty, print_ty)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is overridden for MIR printing because we only want to hide alloc ids from users, not
|
||||||
|
/// from MIR where it is actually useful.
|
||||||
|
fn pretty_print_const_pointer(
|
||||||
|
mut self,
|
||||||
|
_: Pointer,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
print_ty: bool,
|
||||||
|
) -> Result<Self::Const, Self::Error> {
|
||||||
|
if print_ty {
|
||||||
|
self.typed_value(
|
||||||
|
|mut this| {
|
||||||
|
this.write_str("&_")?;
|
||||||
|
Ok(this)
|
||||||
|
},
|
||||||
|
|this| this.print_type(ty),
|
||||||
|
": ",
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
self.write_str("&_")?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pretty_print_byte_str(mut self, byte_str: &'tcx [u8]) -> Result<Self::Const, Self::Error> {
|
||||||
|
define_scoped_cx!(self);
|
||||||
|
p!(write("b\""));
|
||||||
|
for &c in byte_str {
|
||||||
|
for e in std::ascii::escape_default(c) {
|
||||||
|
self.write_char(e as char)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p!(write("\""));
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
fn pretty_print_const_value(
|
fn pretty_print_const_value(
|
||||||
mut self,
|
mut self,
|
||||||
ct: ConstValue<'tcx>,
|
ct: ConstValue<'tcx>,
|
||||||
|
@ -906,113 +1114,55 @@ pub trait PrettyPrinter<'tcx>:
|
||||||
return Ok(self);
|
return Ok(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
let u8 = self.tcx().types.u8;
|
let u8_type = self.tcx().types.u8;
|
||||||
|
|
||||||
match (ct, &ty.kind) {
|
match (ct, &ty.kind) {
|
||||||
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Bool) => {
|
(ConstValue::Scalar(scalar), _) => self.pretty_print_const_scalar(scalar, ty, print_ty),
|
||||||
p!(write("{}", if data == 0 { "false" } else { "true" }))
|
(
|
||||||
}
|
ConstValue::Slice { data, start, end },
|
||||||
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Float(ast::FloatTy::F32)) => {
|
ty::Ref(_, ty::TyS { kind: ty::Slice(t), .. }, _),
|
||||||
p!(write("{}f32", Single::from_bits(data)))
|
) if *t == u8_type => {
|
||||||
}
|
|
||||||
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Float(ast::FloatTy::F64)) => {
|
|
||||||
p!(write("{}f64", Double::from_bits(data)))
|
|
||||||
}
|
|
||||||
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Uint(ui)) => {
|
|
||||||
let bit_size = Integer::from_attr(&self.tcx(), UnsignedInt(*ui)).size();
|
|
||||||
let max = truncate(u128::MAX, bit_size);
|
|
||||||
|
|
||||||
let ui_str = ui.name_str();
|
|
||||||
if data == max {
|
|
||||||
p!(write("std::{}::MAX", ui_str))
|
|
||||||
} else {
|
|
||||||
p!(write("{}{}", data, ui_str))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Int(i)) => {
|
|
||||||
let bit_size = Integer::from_attr(&self.tcx(), SignedInt(*i)).size().bits() as u128;
|
|
||||||
let min = 1u128 << (bit_size - 1);
|
|
||||||
let max = min - 1;
|
|
||||||
|
|
||||||
let ty = self.tcx().lift(&ty).unwrap();
|
|
||||||
let size = self.tcx().layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size;
|
|
||||||
let i_str = i.name_str();
|
|
||||||
match data {
|
|
||||||
d if d == min => p!(write("std::{}::MIN", i_str)),
|
|
||||||
d if d == max => p!(write("std::{}::MAX", i_str)),
|
|
||||||
_ => p!(write("{}{}", sign_extend(data, size) as i128, i_str)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(ConstValue::Scalar(Scalar::Raw { data, .. }), ty::Char) => {
|
|
||||||
p!(write("{:?}", ::std::char::from_u32(data as u32).unwrap()))
|
|
||||||
}
|
|
||||||
(ConstValue::Scalar(_), ty::RawPtr(_)) => p!(write("{{pointer}}")),
|
|
||||||
(ConstValue::Scalar(Scalar::Ptr(ptr)), ty::FnPtr(_)) => {
|
|
||||||
let instance = {
|
|
||||||
let alloc_map = self.tcx().alloc_map.lock();
|
|
||||||
alloc_map.unwrap_fn(ptr.alloc_id)
|
|
||||||
};
|
|
||||||
p!(print_value_path(instance.def_id(), instance.substs));
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
let printed = if let ty::Ref(_, ref_ty, _) = ty.kind {
|
|
||||||
let byte_str = match (ct, &ref_ty.kind) {
|
|
||||||
(ConstValue::Scalar(Scalar::Ptr(ptr)), ty::Array(t, n)) if *t == u8 => {
|
|
||||||
let n = n.eval_usize(self.tcx(), ty::ParamEnv::empty());
|
|
||||||
Some(
|
|
||||||
self.tcx()
|
|
||||||
.alloc_map
|
|
||||||
.lock()
|
|
||||||
.unwrap_memory(ptr.alloc_id)
|
|
||||||
.get_bytes(&self.tcx(), ptr, Size::from_bytes(n))
|
|
||||||
.unwrap(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
(ConstValue::Slice { data, start, end }, ty::Slice(t)) if *t == u8 => {
|
|
||||||
// The `inspect` here is okay since we checked the bounds, and there are
|
// The `inspect` here is okay since we checked the bounds, and there are
|
||||||
// no relocations (we have an active slice reference here). We don't use
|
// no relocations (we have an active slice reference here). We don't use
|
||||||
// this result to affect interpreter execution.
|
// this result to affect interpreter execution.
|
||||||
Some(data.inspect_with_undef_and_ptr_outside_interpreter(start..end))
|
let byte_str = data.inspect_with_undef_and_ptr_outside_interpreter(start..end);
|
||||||
|
self.pretty_print_byte_str(byte_str)
|
||||||
}
|
}
|
||||||
_ => None,
|
(
|
||||||
};
|
ConstValue::Slice { data, start, end },
|
||||||
|
ty::Ref(_, ty::TyS { kind: ty::Str, .. }, _),
|
||||||
if let Some(byte_str) = byte_str {
|
) => {
|
||||||
p!(write("b\""));
|
|
||||||
for &c in byte_str {
|
|
||||||
for e in std::ascii::escape_default(c) {
|
|
||||||
self.write_char(e as char)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p!(write("\""));
|
|
||||||
true
|
|
||||||
} else if let (ConstValue::Slice { data, start, end }, ty::Str) =
|
|
||||||
(ct, &ref_ty.kind)
|
|
||||||
{
|
|
||||||
// The `inspect` here is okay since we checked the bounds, and there are no
|
// The `inspect` here is okay since we checked the bounds, and there are no
|
||||||
// relocations (we have an active `str` reference here). We don't use this
|
// relocations (we have an active `str` reference here). We don't use this
|
||||||
// result to affect interpreter execution.
|
// result to affect interpreter execution.
|
||||||
let slice = data.inspect_with_undef_and_ptr_outside_interpreter(start..end);
|
let slice = data.inspect_with_undef_and_ptr_outside_interpreter(start..end);
|
||||||
let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri");
|
let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri");
|
||||||
p!(write("{:?}", s));
|
p!(write("{:?}", s));
|
||||||
true
|
Ok(self)
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
} else {
|
(ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => {
|
||||||
false
|
let n = n.val.try_to_bits(self.tcx().data_layout.pointer_size).unwrap();
|
||||||
};
|
// cast is ok because we already checked for pointer size (32 or 64 bit) above
|
||||||
if !printed {
|
let n = Size::from_bytes(n as u64);
|
||||||
|
let ptr = Pointer::new(AllocId(0), offset);
|
||||||
|
|
||||||
|
let byte_str = alloc.get_bytes(&self.tcx(), ptr, n).unwrap();
|
||||||
|
p!(write("*"));
|
||||||
|
p!(pretty_print_byte_str(byte_str));
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
// FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading
|
||||||
|
// their fields instead of just dumping the memory.
|
||||||
|
_ => {
|
||||||
// fallback
|
// fallback
|
||||||
p!(write("{:?}", ct));
|
p!(write("{:?}", ct));
|
||||||
if print_ty {
|
if print_ty {
|
||||||
p!(write(": "), print(ty));
|
p!(write(": "), print(ty));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HACK(eddyb) boxed to avoid moving around a large struct by-value.
|
// HACK(eddyb) boxed to avoid moving around a large struct by-value.
|
||||||
|
@ -1024,6 +1174,7 @@ pub struct FmtPrinterData<'a, 'tcx, F> {
|
||||||
|
|
||||||
empty_path: bool,
|
empty_path: bool,
|
||||||
in_value: bool,
|
in_value: bool,
|
||||||
|
pub print_alloc_ids: bool,
|
||||||
|
|
||||||
used_region_names: FxHashSet<Symbol>,
|
used_region_names: FxHashSet<Symbol>,
|
||||||
region_index: usize,
|
region_index: usize,
|
||||||
|
@ -1054,6 +1205,7 @@ impl<F> FmtPrinter<'a, 'tcx, F> {
|
||||||
fmt,
|
fmt,
|
||||||
empty_path: false,
|
empty_path: false,
|
||||||
in_value: ns == Namespace::ValueNS,
|
in_value: ns == Namespace::ValueNS,
|
||||||
|
print_alloc_ids: false,
|
||||||
used_region_names: Default::default(),
|
used_region_names: Default::default(),
|
||||||
region_index: 0,
|
region_index: 0,
|
||||||
binder_depth: 0,
|
binder_depth: 0,
|
||||||
|
@ -1326,6 +1478,22 @@ impl<F: fmt::Write> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> {
|
||||||
self.pretty_in_binder(value)
|
self.pretty_in_binder(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn typed_value(
|
||||||
|
mut self,
|
||||||
|
f: impl FnOnce(Self) -> Result<Self, Self::Error>,
|
||||||
|
t: impl FnOnce(Self) -> Result<Self, Self::Error>,
|
||||||
|
conversion: &str,
|
||||||
|
) -> Result<Self::Const, Self::Error> {
|
||||||
|
self.write_str("{")?;
|
||||||
|
self = f(self)?;
|
||||||
|
self.write_str(conversion)?;
|
||||||
|
let was_in_value = std::mem::replace(&mut self.in_value, false);
|
||||||
|
self = t(self)?;
|
||||||
|
self.in_value = was_in_value;
|
||||||
|
self.write_str("}")?;
|
||||||
|
Ok(self)
|
||||||
|
}
|
||||||
|
|
||||||
fn generic_delimiters(
|
fn generic_delimiters(
|
||||||
mut self,
|
mut self,
|
||||||
f: impl FnOnce(Self) -> Result<Self, Self::Error>,
|
f: impl FnOnce(Self) -> Result<Self, Self::Error>,
|
||||||
|
@ -1382,6 +1550,28 @@ impl<F: fmt::Write> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> {
|
||||||
ty::ReStatic | ty::ReEmpty(_) | ty::ReClosureBound(_) => true,
|
ty::ReStatic | ty::ReEmpty(_) | ty::ReClosureBound(_) => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn pretty_print_const_pointer(
|
||||||
|
self,
|
||||||
|
p: Pointer,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
print_ty: bool,
|
||||||
|
) -> Result<Self::Const, Self::Error> {
|
||||||
|
let print = |mut this: Self| {
|
||||||
|
define_scoped_cx!(this);
|
||||||
|
if this.print_alloc_ids {
|
||||||
|
p!(write("{:?}", p));
|
||||||
|
} else {
|
||||||
|
p!(write("&_"));
|
||||||
|
}
|
||||||
|
Ok(this)
|
||||||
|
};
|
||||||
|
if print_ty {
|
||||||
|
self.typed_value(print, |this| this.print_type(ty), ": ")
|
||||||
|
} else {
|
||||||
|
print(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HACK(eddyb) limited to `FmtPrinter` because of `region_highlight_mode`.
|
// HACK(eddyb) limited to `FmtPrinter` because of `region_highlight_mode`.
|
||||||
|
|
|
@ -157,6 +157,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> {
|
impl PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> {
|
||||||
fn region_should_not_be_omitted(&self, _region: ty::Region<'_>) -> bool {
|
fn region_should_not_be_omitted(&self, _region: ty::Region<'_>) -> bool {
|
||||||
false
|
false
|
||||||
|
|
|
@ -3,18 +3,20 @@
|
||||||
|
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
|
|
||||||
use rustc::ty::layout::{
|
|
||||||
self, HasDataLayout, IntegerExt, LayoutOf, PrimitiveExt, Size, TyLayout, VariantIdx,
|
|
||||||
};
|
|
||||||
use rustc::{mir, ty};
|
|
||||||
|
|
||||||
use super::{InterpCx, MPlaceTy, Machine, MemPlace, Place, PlaceTy};
|
use super::{InterpCx, MPlaceTy, Machine, MemPlace, Place, PlaceTy};
|
||||||
pub use rustc::mir::interpret::ScalarMaybeUndef;
|
pub use rustc::mir::interpret::ScalarMaybeUndef;
|
||||||
use rustc::mir::interpret::{
|
use rustc::mir::interpret::{
|
||||||
sign_extend, truncate, AllocId, ConstValue, GlobalId, InterpResult, Pointer, Scalar,
|
sign_extend, truncate, AllocId, ConstValue, GlobalId, InterpResult, Pointer, Scalar,
|
||||||
};
|
};
|
||||||
use rustc_ast::ast;
|
use rustc::ty::layout::{
|
||||||
|
self, HasDataLayout, IntegerExt, LayoutOf, PrimitiveExt, Size, TyLayout, VariantIdx,
|
||||||
|
};
|
||||||
|
use rustc::ty::print::{FmtPrinter, PrettyPrinter, Printer};
|
||||||
|
use rustc::ty::Ty;
|
||||||
|
use rustc::{mir, ty};
|
||||||
|
use rustc_hir::def::Namespace;
|
||||||
use rustc_macros::HashStable;
|
use rustc_macros::HashStable;
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
/// An `Immediate` represents a single immediate self-contained Rust value.
|
/// An `Immediate` represents a single immediate self-contained Rust value.
|
||||||
///
|
///
|
||||||
|
@ -92,47 +94,44 @@ pub struct ImmTy<'tcx, Tag = ()> {
|
||||||
pub layout: TyLayout<'tcx>,
|
pub layout: TyLayout<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// `Tag: Copy` because some methods on `Scalar` consume them by value
|
|
||||||
impl<Tag: Copy> std::fmt::Display for ImmTy<'tcx, Tag> {
|
impl<Tag: Copy> std::fmt::Display for ImmTy<'tcx, Tag> {
|
||||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match &self.imm {
|
/// Helper function for printing a scalar to a FmtPrinter
|
||||||
// We cannot use `to_bits_or_ptr` as we do not have a `tcx`.
|
fn p<'a, 'tcx, F: std::fmt::Write, Tag>(
|
||||||
// So we use `is_bits` and circumvent a bunch of sanity checking -- but
|
cx: FmtPrinter<'a, 'tcx, F>,
|
||||||
// this is anyway only for printing.
|
s: ScalarMaybeUndef<Tag>,
|
||||||
Immediate::Scalar(ScalarMaybeUndef::Scalar(s)) if s.is_ptr() => {
|
ty: Ty<'tcx>,
|
||||||
fmt.write_str("{pointer}")
|
) -> Result<FmtPrinter<'a, 'tcx, F>, std::fmt::Error> {
|
||||||
|
match s {
|
||||||
|
ScalarMaybeUndef::Scalar(s) => {
|
||||||
|
cx.pretty_print_const_scalar(s.erase_tag(), ty, true)
|
||||||
}
|
}
|
||||||
Immediate::Scalar(ScalarMaybeUndef::Scalar(s)) => {
|
ScalarMaybeUndef::Undef => cx.typed_value(
|
||||||
let s = s.assert_bits(self.layout.size);
|
|mut this| {
|
||||||
match self.layout.ty.kind {
|
this.write_str("{undef ")?;
|
||||||
ty::Int(_) => {
|
Ok(this)
|
||||||
return write!(fmt, "{}", super::sign_extend(s, self.layout.size) as i128,);
|
},
|
||||||
}
|
|this| this.print_type(ty),
|
||||||
ty::Uint(_) => return write!(fmt, "{}", s),
|
" ",
|
||||||
ty::Bool if s == 0 => return fmt.write_str("false"),
|
),
|
||||||
ty::Bool if s == 1 => return fmt.write_str("true"),
|
|
||||||
ty::Char => {
|
|
||||||
if let Some(c) = u32::try_from(s).ok().and_then(std::char::from_u32) {
|
|
||||||
return write!(fmt, "{}", c);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::Float(ast::FloatTy::F32) => {
|
ty::tls::with(|tcx| {
|
||||||
if let Ok(u) = u32::try_from(s) {
|
match self.imm {
|
||||||
return write!(fmt, "{}", f32::from_bits(u));
|
Immediate::Scalar(s) => {
|
||||||
|
if let Some(ty) = tcx.lift(&self.layout.ty) {
|
||||||
|
let cx = FmtPrinter::new(tcx, f, Namespace::ValueNS);
|
||||||
|
p(cx, s, ty)?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
write!(f, "{:?}: {}", s.erase_tag(), self.layout.ty)
|
||||||
|
}
|
||||||
|
Immediate::ScalarPair(a, b) => {
|
||||||
|
// FIXME(oli-obk): at least print tuples and slices nicely
|
||||||
|
write!(f, "({:?}, {:?}): {}", a.erase_tag(), b.erase_tag(), self.layout.ty,)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::Float(ast::FloatTy::F64) => {
|
})
|
||||||
if let Ok(u) = u64::try_from(s) {
|
|
||||||
return write!(fmt, "{}", f64::from_bits(u));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
write!(fmt, "{:x}", s)
|
|
||||||
}
|
|
||||||
Immediate::Scalar(ScalarMaybeUndef::Undef) => fmt.write_str("{undef}"),
|
|
||||||
Immediate::ScalarPair(..) => fmt.write_str("{wide pointer or tuple}"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ fn main() {}
|
||||||
// START rustc.FOO.PromoteTemps.before.mir
|
// START rustc.FOO.PromoteTemps.before.mir
|
||||||
// bb0: {
|
// bb0: {
|
||||||
// ...
|
// ...
|
||||||
// _5 = const Scalar(alloc1+0) : &i32;
|
// _5 = const {alloc1+0: &i32};
|
||||||
// _4 = &(*_5);
|
// _4 = &(*_5);
|
||||||
// _3 = [move _4];
|
// _3 = [move _4];
|
||||||
// _2 = &_3;
|
// _2 = &_3;
|
||||||
|
@ -31,7 +31,7 @@ fn main() {}
|
||||||
// START rustc.BAR.PromoteTemps.before.mir
|
// START rustc.BAR.PromoteTemps.before.mir
|
||||||
// bb0: {
|
// bb0: {
|
||||||
// ...
|
// ...
|
||||||
// _5 = const Scalar(alloc0+0) : &i32;
|
// _5 = const {alloc0+0: &i32};
|
||||||
// _4 = &(*_5);
|
// _4 = &(*_5);
|
||||||
// _3 = [move _4];
|
// _3 = [move _4];
|
||||||
// _2 = &_3;
|
// _2 = &_3;
|
||||||
|
|
|
@ -31,7 +31,7 @@ fn main() {
|
||||||
// START rustc.main.ConstProp.after.mir
|
// START rustc.main.ConstProp.after.mir
|
||||||
// bb0: {
|
// bb0: {
|
||||||
// ...
|
// ...
|
||||||
// _3 = const Scalar(0x01) : std::option::Option<bool>;
|
// _3 = const {transmute(0x01): std::option::Option<bool>};
|
||||||
// _4 = const 1isize;
|
// _4 = const 1isize;
|
||||||
// switchInt(const 1isize) -> [1isize: bb2, otherwise: bb1];
|
// switchInt(const 1isize) -> [1isize: bb2, otherwise: bb1];
|
||||||
// }
|
// }
|
||||||
|
|
|
@ -29,7 +29,7 @@ fn main() {
|
||||||
// START rustc.main.ConstProp.after.mir
|
// START rustc.main.ConstProp.after.mir
|
||||||
// bb0: {
|
// bb0: {
|
||||||
// ...
|
// ...
|
||||||
// _3 = const Scalar(<ZST>) : ();
|
// _3 = const ();
|
||||||
// _2 = (move _3, const 0u8, const 0u8);
|
// _2 = (move _3, const 0u8, const 0u8);
|
||||||
// ...
|
// ...
|
||||||
// _1 = const encode(move _2) -> bb1;
|
// _1 = const encode(move _2) -> bb1;
|
||||||
|
|
|
@ -10,10 +10,10 @@ fn main() {
|
||||||
// START rustc.main.ConstProp.before.mir
|
// START rustc.main.ConstProp.before.mir
|
||||||
// bb0: {
|
// bb0: {
|
||||||
// ...
|
// ...
|
||||||
// _3 = const Scalar(alloc0+0) : &u8;
|
// _3 = const {alloc0+0: &u8};
|
||||||
// _2 = (*_3);
|
// _2 = (*_3);
|
||||||
// ...
|
// ...
|
||||||
// _5 = const Scalar(alloc0+0) : &u8;
|
// _5 = const {alloc0+0: &u8};
|
||||||
// _4 = (*_5);
|
// _4 = (*_5);
|
||||||
// _1 = Add(move _2, move _4);
|
// _1 = Add(move _2, move _4);
|
||||||
// ...
|
// ...
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
// compile-flags: -C overflow-checks=no
|
// compile-flags: -C overflow-checks=no
|
||||||
|
|
||||||
fn use_zst(_: ((), ())) { }
|
fn use_zst(_: ((), ())) {}
|
||||||
|
|
||||||
struct Temp {
|
struct Temp {
|
||||||
x: u8
|
x: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn use_u8(_: u8) { }
|
fn use_u8(_: u8) {}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let ((), ()) = ((), ());
|
let ((), ()) = ((), ());
|
||||||
use_zst(((), ()));
|
use_zst(((), ()));
|
||||||
|
|
||||||
use_u8((Temp { x : 40 }).x + 2);
|
use_u8((Temp { x: 40 }).x + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// END RUST SOURCE
|
// END RUST SOURCE
|
||||||
|
@ -35,28 +35,28 @@ fn main() {
|
||||||
// bb0: {
|
// bb0: {
|
||||||
// StorageLive(_1);
|
// StorageLive(_1);
|
||||||
// StorageLive(_2);
|
// StorageLive(_2);
|
||||||
// _2 = const Scalar(<ZST>) : ();
|
// _2 = const ();
|
||||||
// StorageLive(_3);
|
// StorageLive(_3);
|
||||||
// _3 = const Scalar(<ZST>) : ();
|
// _3 = const ();
|
||||||
// _1 = const Scalar(<ZST>) : ((), ());
|
// _1 = const {transmute(()): ((), ())};
|
||||||
// StorageDead(_3);
|
// StorageDead(_3);
|
||||||
// StorageDead(_2);
|
// StorageDead(_2);
|
||||||
// StorageDead(_1);
|
// StorageDead(_1);
|
||||||
// StorageLive(_4);
|
// StorageLive(_4);
|
||||||
// StorageLive(_6);
|
// StorageLive(_6);
|
||||||
// _6 = const Scalar(<ZST>) : ();
|
// _6 = const ();
|
||||||
// StorageLive(_7);
|
// StorageLive(_7);
|
||||||
// _7 = const Scalar(<ZST>) : ();
|
// _7 = const ();
|
||||||
// StorageDead(_7);
|
// StorageDead(_7);
|
||||||
// StorageDead(_6);
|
// StorageDead(_6);
|
||||||
// _4 = const use_zst(const Scalar(<ZST>) : ((), ())) -> bb1;
|
// _4 = const use_zst(const {transmute(()): ((), ())}) -> bb1;
|
||||||
// }
|
// }
|
||||||
// bb1: {
|
// bb1: {
|
||||||
// StorageDead(_4);
|
// StorageDead(_4);
|
||||||
// StorageLive(_8);
|
// StorageLive(_8);
|
||||||
// StorageLive(_10);
|
// StorageLive(_10);
|
||||||
// StorageLive(_11);
|
// StorageLive(_11);
|
||||||
// _11 = const Scalar(0x28) : Temp;
|
// _11 = const {transmute(0x28) : Temp};
|
||||||
// _10 = const 40u8;
|
// _10 = const 40u8;
|
||||||
// StorageDead(_10);
|
// StorageDead(_10);
|
||||||
// _8 = const use_u8(const 42u8) -> bb2;
|
// _8 = const use_u8(const 42u8) -> bb2;
|
||||||
|
@ -75,7 +75,7 @@ fn main() {
|
||||||
// }
|
// }
|
||||||
// bb0: {
|
// bb0: {
|
||||||
// StorageLive(_1);
|
// StorageLive(_1);
|
||||||
// _1 = const use_zst(const Scalar(<ZST>) : ((), ())) -> bb1;
|
// _1 = const use_zst(const {transmute(()): ((), ())}) -> bb1;
|
||||||
// }
|
// }
|
||||||
// bb1: {
|
// bb1: {
|
||||||
// StorageDead(_1);
|
// StorageDead(_1);
|
||||||
|
|
|
@ -10,7 +10,7 @@ error[E0282]: type annotations needed
|
||||||
--> $DIR/cannot-infer-const-args.rs:9:5
|
--> $DIR/cannot-infer-const-args.rs:9:5
|
||||||
|
|
|
|
||||||
LL | foo();
|
LL | foo();
|
||||||
| ^^^ cannot infer type for fn item `fn() -> usize {foo::<_: usize>}`
|
| ^^^ cannot infer type for fn item `fn() -> usize {foo::<{_: usize}>}`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -7,5 +7,5 @@
|
||||||
struct S<const N: usize>;
|
struct S<const N: usize>;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
assert_eq!(std::any::type_name::<S<3>>(), "const_generic_type_name::S<3usize>");
|
assert_eq!(std::any::type_name::<S<3>>(), "const_generic_type_name::S<3>");
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,12 @@ error[E0308]: mismatched types
|
||||||
--> $DIR/fn-const-param-infer.rs:16:31
|
--> $DIR/fn-const-param-infer.rs:16:31
|
||||||
|
|
|
|
||||||
LL | let _: Checked<not_one> = Checked::<not_two>;
|
LL | let _: Checked<not_one> = Checked::<not_two>;
|
||||||
| ---------------- ^^^^^^^^^^^^^^^^^^ expected `not_one`, found `not_two`
|
| ---------------- ^^^^^^^^^^^^^^^^^^ expected `{not_one as fn(usize) -> bool}`, found `{not_two as fn(usize) -> bool}`
|
||||||
| |
|
| |
|
||||||
| expected due to this
|
| expected due to this
|
||||||
|
|
|
|
||||||
= note: expected struct `Checked<not_one>`
|
= note: expected struct `Checked<{not_one as fn(usize) -> bool}>`
|
||||||
found struct `Checked<not_two>`
|
found struct `Checked<{not_two as fn(usize) -> bool}>`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/fn-const-param-infer.rs:20:24
|
--> $DIR/fn-const-param-infer.rs:20:24
|
||||||
|
@ -36,12 +36,12 @@ error[E0308]: mismatched types
|
||||||
--> $DIR/fn-const-param-infer.rs:25:40
|
--> $DIR/fn-const-param-infer.rs:25:40
|
||||||
|
|
|
|
||||||
LL | let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>;
|
LL | let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>;
|
||||||
| ------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `generic::<u32>`, found `generic::<u16>`
|
| ------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{generic::<u32> as fn(usize) -> bool}`, found `{generic::<u16> as fn(usize) -> bool}`
|
||||||
| |
|
| |
|
||||||
| expected due to this
|
| expected due to this
|
||||||
|
|
|
|
||||||
= note: expected struct `Checked<generic::<u32>>`
|
= note: expected struct `Checked<{generic::<u32> as fn(usize) -> bool}>`
|
||||||
found struct `Checked<generic::<u16>>`
|
found struct `Checked<{generic::<u16> as fn(usize) -> bool}>`
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,6 @@
|
||||||
struct Const<const P: *const u32>;
|
struct Const<const P: *const u32>;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let _: Const<{15 as *const _}> = Const::<{10 as *const _}>; //~ mismatched types
|
let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>; //~ mismatched types
|
||||||
let _: Const<{10 as *const _}> = Const::<{10 as *const _}>;
|
let _: Const<{ 10 as *const _ }> = Const::<{ 10 as *const _ }>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,15 +7,15 @@ LL | #![feature(const_generics, const_compare_raw_pointers)]
|
||||||
= note: `#[warn(incomplete_features)]` on by default
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/raw-ptr-const-param.rs:7:38
|
--> $DIR/raw-ptr-const-param.rs:7:40
|
||||||
|
|
|
|
||||||
LL | let _: Const<{15 as *const _}> = Const::<{10 as *const _}>;
|
LL | let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>;
|
||||||
| ----------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{pointer}`, found `{pointer}`
|
| ------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}`
|
||||||
| |
|
| |
|
||||||
| expected due to this
|
| expected due to this
|
||||||
|
|
|
|
||||||
= note: expected struct `Const<{pointer}>`
|
= note: expected struct `Const<{0xf as *const u32}>`
|
||||||
found struct `Const<{pointer}>`
|
found struct `Const<{0xa as *const u32}>`
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ error: any use of this value will cause an error
|
||||||
LL | intrinsics::ptr_offset_from(self, origin)
|
LL | intrinsics::ptr_offset_from(self, origin)
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
| |
|
| |
|
||||||
| exact_div: 1 cannot be divided by 2 without remainder
|
| exact_div: 1isize cannot be divided by 2isize without remainder
|
||||||
| inside call to `std::ptr::const_ptr::<impl *const u16>::offset_from` at $DIR/offset_from_ub.rs:36:14
|
| inside call to `std::ptr::const_ptr::<impl *const u16>::offset_from` at $DIR/offset_from_ub.rs:36:14
|
||||||
|
|
|
|
||||||
::: $DIR/offset_from_ub.rs:31:1
|
::: $DIR/offset_from_ub.rs:31:1
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue