initial_rustc: PathBuf,
initial_cargo: PathBuf,
- // Probed tools at runtime
- lldb_version: Option<String>,
- lldb_python_dir: Option<String>,
-
// Runtime state filled in later on
// C/C++ compilers and archiver for all targets
cc: HashMap<Interned<String>, cc::Tool>,
ar: HashMap::new(),
ranlib: HashMap::new(),
crates: HashMap::new(),
- lldb_version: None,
- lldb_python_dir: None,
is_sudo,
ci_env: CiEnv::current(),
delayed_failures: RefCell::new(Vec::new()),
}
}
- let run = |cmd: &mut Command| {
- cmd.output().map(|output| {
- String::from_utf8_lossy(&output.stdout)
- .lines().next().unwrap_or_else(|| {
- panic!("{:?} failed {:?}", cmd, output)
- }).to_string()
- })
- };
- build.lldb_version = run(Command::new("lldb").arg("--version")).ok();
- if build.lldb_version.is_some() {
- build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok();
- }
-
if let Some(ref s) = build.config.ccache {
cmd_finder.must_have(s);
}
if let Some(ref gdb) = builder.config.gdb {
cmd.arg("--gdb").arg(gdb);
}
- if let Some(ref vers) = builder.lldb_version {
+
+ let run = |cmd: &mut Command| {
+ cmd.output().map(|output| {
+ String::from_utf8_lossy(&output.stdout)
+ .lines().next().unwrap_or_else(|| {
+ panic!("{:?} failed {:?}", cmd, output)
+ }).to_string()
+ })
+ };
+ let lldb_exe = if builder.config.lldb_enabled && !target.contains("emscripten") {
+ // Test against the lldb that was just built.
+ builder.llvm_out(target)
+ .join("bin")
+ .join("lldb")
+ } else {
+ PathBuf::from("lldb")
+ };
+ let lldb_version = Command::new(&lldb_exe)
+ .arg("--version")
+ .output()
+ .map(|output| { String::from_utf8_lossy(&output.stdout).to_string() })
+ .ok();
+ if let Some(ref vers) = lldb_version {
cmd.arg("--lldb-version").arg(vers);
- }
- if let Some(ref dir) = builder.lldb_python_dir {
- cmd.arg("--lldb-python-dir").arg(dir);
+ let lldb_python_dir = run(Command::new(&lldb_exe).arg("-P")).ok();
+ if let Some(ref dir) = lldb_python_dir {
+ cmd.arg("--lldb-python-dir").arg(dir);
+ }
}
// Get paths from cmd args
#[stable(feature = "rust1", since = "1.0.0")]
impl ToOwned for str {
type Owned = String;
+ #[inline]
fn to_owned(&self) -> String {
unsafe { String::from_utf8_unchecked(self.as_bytes().to_owned()) }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> From<&'a str> for String {
+ #[inline]
fn from(s: &'a str) -> String {
s.to_owned()
}
}
}
-impl_stable_hash_for!(struct mir::interpret::Pointer {
- alloc_id,
- offset
-});
+impl<'a, Tag> HashStable<StableHashingContext<'a>>
+for ::mir::interpret::Pointer<Tag>
+where Tag: HashStable<StableHashingContext<'a>>
+{
+ fn hash_stable<W: StableHasherResult>(&self,
+ hcx: &mut StableHashingContext<'a>,
+ hasher: &mut StableHasher<W>) {
+ let ::mir::interpret::Pointer { alloc_id, offset, tag } = self;
+ alloc_id.hash_stable(hcx, hasher);
+ offset.hash_stable(hcx, hasher);
+ tag.hash_stable(hcx, hasher);
+ }
+}
+
+impl<'a, Tag> HashStable<StableHashingContext<'a>>
+for ::mir::interpret::Scalar<Tag>
+where Tag: HashStable<StableHashingContext<'a>>
+{
+ fn hash_stable<W: StableHasherResult>(&self,
+ hcx: &mut StableHashingContext<'a>,
+ hasher: &mut StableHasher<W>) {
+ use mir::interpret::Scalar::*;
+
+ mem::discriminant(self).hash_stable(hcx, hasher);
+ match self {
+ Bits { bits, size } => {
+ bits.hash_stable(hcx, hasher);
+ size.hash_stable(hcx, hasher);
+ },
+ Ptr(ptr) => ptr.hash_stable(hcx, hasher),
+ }
+ }
+}
impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::AllocId {
fn hash_stable<W: StableHasherResult>(
Mutable
});
-
-impl<'a> HashStable<StableHashingContext<'a>>
-for ::mir::interpret::Scalar {
- fn hash_stable<W: StableHasherResult>(&self,
- hcx: &mut StableHashingContext<'a>,
- hasher: &mut StableHasher<W>) {
- use mir::interpret::Scalar::*;
-
- mem::discriminant(self).hash_stable(hcx, hasher);
- match *self {
- Bits { bits, size } => {
- bits.hash_stable(hcx, hasher);
- size.hash_stable(hcx, hasher);
- },
- Ptr(ptr) => ptr.hash_stable(hcx, hasher),
- }
- }
-}
-
impl_stable_hash_for!(struct ty::Const<'tcx> {
ty,
val
a.hash_stable(hcx, hasher);
b.hash_stable(hcx, hasher)
},
+ FunctionRetMismatch(a, b) => {
+ a.hash_stable(hcx, hasher);
+ b.hash_stable(hcx, hasher)
+ },
NoMirFor(ref s) => s.hash_stable(hcx, hasher),
UnterminatedCString(ptr) => ptr.hash_stable(hcx, hasher),
PointerOutOfBounds {
FunctionAbiMismatch(Abi, Abi),
FunctionArgMismatch(Ty<'tcx>, Ty<'tcx>),
+ FunctionRetMismatch(Ty<'tcx>, Ty<'tcx>),
FunctionArgCountMismatch,
NoMirFor(String),
UnterminatedCString(Pointer),
use self::EvalErrorKind::*;
match *self {
MachineError(ref inner) => inner,
- FunctionAbiMismatch(..) | FunctionArgMismatch(..) | FunctionArgCountMismatch =>
+ FunctionAbiMismatch(..) | FunctionArgMismatch(..) | FunctionRetMismatch(..)
+ | FunctionArgCountMismatch =>
"tried to call a function through a function pointer of incompatible type",
InvalidMemoryAccess =>
"tried to access memory through an invalid pointer",
write!(f, "tried to call a function with argument of type {:?} \
passing data of type {:?}",
callee_ty, caller_ty),
+ FunctionRetMismatch(caller_ty, callee_ty) =>
+ write!(f, "tried to call a function with return type {:?} \
+ passing return place of type {:?}",
+ callee_ty, caller_ty),
FunctionArgCountMismatch =>
write!(f, "tried to call a function with incorrect number of arguments"),
BoundsCheck { ref len, ref index } =>
/// each context.
///
/// Defaults to the index based and loosely coupled AllocId.
+///
+/// Pointer is also generic over the `Tag` associated with each pointer,
+/// which is used to do provenance tracking during execution.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
-pub struct Pointer<Id=AllocId> {
+pub struct Pointer<Tag=(),Id=AllocId> {
pub alloc_id: Id,
pub offset: Size,
+ pub tag: Tag,
}
/// Produces a `Pointer` which points to the beginning of the Allocation
impl From<AllocId> for Pointer {
+ #[inline(always)]
fn from(alloc_id: AllocId) -> Self {
Pointer::new(alloc_id, Size::ZERO)
}
}
-impl<'tcx> Pointer {
+impl<'tcx> Pointer<()> {
+ #[inline(always)]
pub fn new(alloc_id: AllocId, offset: Size) -> Self {
- Pointer { alloc_id, offset }
+ Pointer { alloc_id, offset, tag: () }
+ }
+
+ #[inline(always)]
+ pub fn with_default_tag<Tag>(self) -> Pointer<Tag>
+ where Tag: Default
+ {
+ Pointer::new_with_tag(self.alloc_id, self.offset, Default::default())
+ }
+}
+
+impl<'tcx, Tag> Pointer<Tag> {
+ #[inline(always)]
+ pub fn new_with_tag(alloc_id: AllocId, offset: Size, tag: Tag) -> Self {
+ Pointer { alloc_id, offset, tag }
}
pub fn wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> Self {
- Pointer::new(
+ Pointer::new_with_tag(
self.alloc_id,
Size::from_bytes(cx.data_layout().wrapping_signed_offset(self.offset.bytes(), i)),
+ self.tag,
)
}
pub fn overflowing_signed_offset<C: HasDataLayout>(self, i: i128, cx: C) -> (Self, bool) {
let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i);
- (Pointer::new(self.alloc_id, Size::from_bytes(res)), over)
+ (Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
}
pub fn signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
- Ok(Pointer::new(
+ Ok(Pointer::new_with_tag(
self.alloc_id,
Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?),
+ self.tag,
))
}
pub fn overflowing_offset<C: HasDataLayout>(self, i: Size, cx: C) -> (Self, bool) {
let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes());
- (Pointer::new(self.alloc_id, Size::from_bytes(res)), over)
+ (Pointer::new_with_tag(self.alloc_id, Size::from_bytes(res), self.tag), over)
}
pub fn offset<C: HasDataLayout>(self, i: Size, cx: C) -> EvalResult<'tcx, Self> {
- Ok(Pointer::new(
+ Ok(Pointer::new_with_tag(
self.alloc_id,
Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?),
+ self.tag
))
}
+
+ #[inline]
+ pub fn erase_tag(self) -> Pointer {
+ Pointer { alloc_id: self.alloc_id, offset: self.offset, tag: () }
+ }
}
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
-pub struct Allocation {
+pub struct Allocation<Tag=()> {
/// The actual bytes of the allocation.
/// Note that the bytes of a pointer represent the offset of the pointer
pub bytes: Vec<u8>,
- /// Maps from byte addresses to allocations.
+ /// Maps from byte addresses to extra data for each pointer.
/// Only the first byte of a pointer is inserted into the map; i.e.,
/// every entry in this map applies to `pointer_size` consecutive bytes starting
/// at the given offset.
- pub relocations: Relocations,
+ pub relocations: Relocations<Tag>,
/// Denotes undefined memory. Reading from undefined memory is forbidden in miri
pub undef_mask: UndefMask,
/// The alignment of the allocation to detect unaligned reads.
pub mutability: Mutability,
}
-impl Allocation {
+impl<Tag> Allocation<Tag> {
/// Creates a read-only allocation initialized by the given bytes
pub fn from_bytes(slice: &[u8], align: Align) -> Self {
let mut undef_mask = UndefMask::new(Size::ZERO);
impl<'tcx> ::serialize::UseSpecializedDecodable for &'tcx Allocation {}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)]
-pub struct Relocations<Id=AllocId>(SortedMap<Size, Id>);
+pub struct Relocations<Tag=(), Id=AllocId>(SortedMap<Size, (Tag, Id)>);
-impl<Id> Relocations<Id> {
+impl<Tag, Id> Relocations<Tag, Id> {
pub fn new() -> Self {
Relocations(SortedMap::new())
}
// The caller must guarantee that the given relocations are already sorted
// by address and contain no duplicates.
- pub fn from_presorted(r: Vec<(Size, Id)>) -> Self {
+ pub fn from_presorted(r: Vec<(Size, (Tag, Id))>) -> Self {
Relocations(SortedMap::from_presorted_elements(r))
}
}
-impl Deref for Relocations {
- type Target = SortedMap<Size, AllocId>;
+impl<Tag> Deref for Relocations<Tag> {
+ type Target = SortedMap<Size, (Tag, AllocId)>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
-impl DerefMut for Relocations {
+impl<Tag> DerefMut for Relocations<Tag> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
}
-impl<'tcx> Scalar {
+/// A `Scalar` represents an immediate, primitive value existing outside of a
+/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
+/// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes
+/// of a simple value or a pointer into another `Allocation`
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
+pub enum Scalar<Tag=(), Id=AllocId> {
+ /// The raw bytes of a simple value.
+ Bits {
+ /// The first `size` bytes are the value.
+ /// Do not try to read less or more bytes that that. The remaining bytes must be 0.
+ size: u8,
+ bits: u128,
+ },
+
+ /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
+ /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the
+ /// relocation and its associated offset together as a `Pointer` here.
+ Ptr(Pointer<Tag, Id>),
+}
+
+impl<'tcx> Scalar<()> {
+ #[inline]
+ pub fn with_default_tag<Tag>(self) -> Scalar<Tag>
+ where Tag: Default
+ {
+ match self {
+ Scalar::Ptr(ptr) => Scalar::Ptr(ptr.with_default_tag()),
+ Scalar::Bits { bits, size } => Scalar::Bits { bits, size },
+ }
+ }
+}
+
+impl<'tcx, Tag> Scalar<Tag> {
+ #[inline]
+ pub fn erase_tag(self) -> Scalar {
+ match self {
+ Scalar::Ptr(ptr) => Scalar::Ptr(ptr.erase_tag()),
+ Scalar::Bits { bits, size } => Scalar::Bits { bits, size },
+ }
+ }
+
#[inline]
pub fn ptr_null(cx: impl HasDataLayout) -> Self {
Scalar::Bits {
}
#[inline]
- pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
+ pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
match self {
Scalar::Bits { bits: 0, .. } => err!(InvalidNullPointerUsage),
Scalar::Bits { .. } => err!(ReadBytesAsPointer),
}
}
-impl From<Pointer> for Scalar {
+impl<Tag> From<Pointer<Tag>> for Scalar<Tag> {
#[inline(always)]
- fn from(ptr: Pointer) -> Self {
+ fn from(ptr: Pointer<Tag>) -> Self {
Scalar::Ptr(ptr)
}
}
-
-/// A `Scalar` represents an immediate, primitive value existing outside of a
-/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
-/// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes
-/// of a simple value or a pointer into another `Allocation`
-#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
-pub enum Scalar<Id=AllocId> {
- /// The raw bytes of a simple value.
- Bits {
- /// The first `size` bytes are the value.
- /// Do not try to read less or more bytes that that. The remaining bytes must be 0.
- size: u8,
- bits: u128,
- },
-
- /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
- /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the
- /// relocation and its associated offset together as a `Pointer` here.
- Ptr(Pointer<Id>),
-}
self.super_ty(ty);
}
- fn visit_canonical_ty(&mut self, ty: & $($mutability)* CanonicalTy<'tcx>) {
+ fn visit_user_ty(&mut self, ty: & $($mutability)* CanonicalTy<'tcx>) {
self.super_canonical_ty(ty);
}
c_ty: & $($mutability)* CanonicalTy<'tcx>,
location: Location) {
self.visit_place(place, PlaceContext::Validate, location);
- self.visit_canonical_ty(c_ty);
+ self.visit_user_ty(c_ty);
}
fn super_place(&mut self,
source_info: *source_info,
});
if let Some(user_ty) = user_ty {
- self.visit_canonical_ty(user_ty);
+ self.visit_user_ty(user_ty);
}
self.visit_source_info(source_info);
self.visit_source_scope(visibility_scope);
tcx.lift(&a)?,
tcx.lift(&b)?,
),
+ FunctionRetMismatch(a, b) => FunctionRetMismatch(
+ tcx.lift(&a)?,
+ tcx.lift(&b)?,
+ ),
FunctionArgCountMismatch => FunctionArgCountMismatch,
NoMirFor(ref s) => NoMirFor(s.clone()),
UnterminatedCString(ptr) => UnterminatedCString(ptr),
let pointer_size = layout.pointer_size.bytes() as usize;
let mut next_offset = 0;
- for &(offset, alloc_id) in alloc.relocations.iter() {
+ for &(offset, ((), alloc_id)) in alloc.relocations.iter() {
let offset = offset.bytes();
assert_eq!(offset as usize as u64, offset);
let offset = offset as usize;
).expect("const_alloc_to_llvm: could not read relocation pointer") as u64;
llvals.push(scalar_to_llvm(
cx,
- Pointer { alloc_id, offset: Size::from_bytes(ptr_offset) }.into(),
+ Pointer::new(alloc_id, Size::from_bytes(ptr_offset)).into(),
&layout::Scalar {
value: layout::Primitive::Pointer,
valid_range: 0..=!0
let ecx = ::rustc_mir::const_eval::mk_eval_cx(tcx, gid.instance, param_env).unwrap();
let result = (|| {
let op = ecx.const_to_op(constant)?;
- let mut todo = vec![(op, Vec::new())];
- let mut seen = FxHashSet();
- seen.insert(op);
- while let Some((op, mut path)) = todo.pop() {
+ let mut ref_tracking = ::rustc_mir::interpret::RefTracking::new(op);
+ while let Some((op, mut path)) = ref_tracking.todo.pop() {
ecx.validate_operand(
op,
&mut path,
- &mut seen,
- &mut todo,
+ Some(&mut ref_tracking),
+ /* const_mode */ true,
)?;
}
Ok(())
debug!("report_mutability_error: act={:?}, acted_on={:?}", act, acted_on);
match the_place_err {
+ // Suggest making an existing shared borrow in a struct definition a mutable borrow.
+ //
+ // This is applicable when we have a deref of a field access to a deref of a local -
+ // something like `*((*_1).0`. The local that we get will be a reference to the
+ // struct we've got a field access of (it must be a reference since there's a deref
+ // after the field access).
+ Place::Projection(box Projection {
+ base: Place::Projection(box Projection {
+ base: Place::Projection(box Projection {
+ base,
+ elem: ProjectionElem::Deref,
+ }),
+ elem: ProjectionElem::Field(field, _),
+ }),
+ elem: ProjectionElem::Deref,
+ }) => {
+ err.span_label(span, format!("cannot {ACT}", ACT = act));
+
+ if let Some((span, message)) = annotate_struct_field(
+ self.infcx.tcx,
+ base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx),
+ field,
+ ) {
+ err.span_suggestion_with_applicability(
+ span,
+ "consider changing this to be mutable",
+ message,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ },
+
// Suggest removing a `&mut` from the use of a mutable reference.
Place::Local(local)
if {
fn is_closure_or_generator(ty: ty::Ty) -> bool {
ty.is_closure() || ty.is_generator()
}
+
+/// Add a suggestion to a struct definition given a field access to a local.
+/// This function expects the local to be a reference to a struct in order to produce a suggestion.
+///
+/// ```text
+/// LL | s: &'a String
+/// | ---------- use `&'a mut String` here to make mutable
+/// ```
+fn annotate_struct_field(
+ tcx: TyCtxt<'cx, 'gcx, 'tcx>,
+ ty: ty::Ty<'tcx>,
+ field: &mir::Field,
+) -> Option<(Span, String)> {
+ // Expect our local to be a reference to a struct of some kind.
+ if let ty::TyKind::Ref(_, ty, _) = ty.sty {
+ if let ty::TyKind::Adt(def, _) = ty.sty {
+ let field = def.all_fields().nth(field.index())?;
+ // Use the HIR types to construct the diagnostic message.
+ let node_id = tcx.hir.as_local_node_id(field.did)?;
+ let node = tcx.hir.find(node_id)?;
+ // Now we're dealing with the actual struct that we're going to suggest a change to,
+ // we can expect a field that is an immutable reference to a type.
+ if let hir::Node::Field(field) = node {
+ if let hir::TyKind::Rptr(lifetime, hir::MutTy {
+ mutbl: hir::Mutability::MutImmutable,
+ ref ty
+ }) = field.ty.node {
+ // Get the snippets in two parts - the named lifetime (if there is one) and
+ // type being referenced, that way we can reconstruct the snippet without loss
+ // of detail.
+ let type_snippet = tcx.sess.source_map().span_to_snippet(ty.span).ok()?;
+ let lifetime_snippet = if !lifetime.is_elided() {
+ format!("{} ", tcx.sess.source_map().span_to_snippet(lifetime.span).ok()?)
+ } else {
+ String::new()
+ };
+
+ return Some((
+ field.ty.span,
+ format!(
+ "&{}mut {}",
+ lifetime_snippet, &*type_snippet,
+ ),
+ ));
+ }
+ }
+ }
+ }
+
+ None
+}
use rustc::ty::subst::Substs;
use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable};
-use rustc::mir::{BasicBlock, Location, Mir, Place, Statement, StatementKind};
+use rustc::mir::{BasicBlock, Location, Mir, Statement, StatementKind};
use rustc::mir::visit::{MutVisitor, TyContext};
use rustc::infer::{InferCtxt, NLLRegionVariableOrigin};
debug!("visit_ty: ty={:?}", ty);
}
+ fn visit_user_ty(&mut self, _ty: &mut CanonicalTy<'tcx>) {
+ // `user_ty` annotations represent the types that the user
+ // wrote in the progarm. We don't want to erase the regions
+ // from these types: rather, we want to add them as
+ // constraints at type-check time.
+ debug!("visit_user_ty: skipping renumber");
+ }
+
fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, location: Location) {
debug!("visit_substs(substs={:?}, location={:?})", substs, location);
debug!("visit_closure_substs: substs={:?}", substs);
}
- fn visit_ascribe_user_ty(
- &mut self,
- _place: &mut Place<'tcx>,
- _variance: &mut ty::Variance,
- _c_ty: &mut CanonicalTy<'tcx>,
- _location: Location,
- ) {
- // User-assert-ty statements represent types that the user added explicitly.
- // We don't want to erase the regions from these types: rather, we want to
- // add them as constraints at type-check time.
- debug!("visit_user_assert_ty: skipping renumber");
- }
-
fn visit_statement(
&mut self,
block: BasicBlock,
) {
for ascription in ascriptions {
let source_info = self.source_info(ascription.span);
+
+ debug!(
+ "adding user ascription at span {:?} of place {:?} and {:?}",
+ source_info.span,
+ ascription.source,
+ ascription.user_ty,
+ );
+
self.cfg.push(
block,
Statement {
use std::fmt;
use std::error::Error;
+use std::borrow::{Borrow, Cow};
+use std::hash::Hash;
+use std::collections::hash_map::Entry;
use rustc::hir::{self, def_id::DefId};
use rustc::mir::interpret::ConstEvalErr;
use rustc::ty::layout::{self, LayoutOf, TyLayout};
use rustc::ty::subst::Subst;
use rustc_data_structures::indexed_vec::IndexVec;
+use rustc_data_structures::fx::FxHashMap;
use syntax::ast::Mutability;
use syntax::source_map::{Span, DUMMY_SP};
use rustc::mir::interpret::{
EvalResult, EvalError, EvalErrorKind, GlobalId,
- Scalar, Allocation, ConstValue,
+ Scalar, Allocation, AllocId, ConstValue,
};
use interpret::{self,
Place, PlaceTy, MemPlace, OpTy, Operand, Value,
}
};
let val = match normalized_op {
- Err(MemPlace { ptr, align, extra }) => {
+ Err(MemPlace { ptr, align, meta }) => {
// extract alloc-offset pair
- assert!(extra.is_none());
+ assert!(meta.is_none());
let ptr = ptr.to_ptr()?;
let alloc = ecx.memory.get(ptr.alloc_id)?;
assert!(alloc.align.abi() >= align.abi());
}
}
+impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxHashMap<K, V> {
+ #[inline(always)]
+ fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool
+ where K: Borrow<Q>
+ {
+ FxHashMap::contains_key(self, k)
+ }
+
+ #[inline(always)]
+ fn insert(&mut self, k: K, v: V) -> Option<V>
+ {
+ FxHashMap::insert(self, k, v)
+ }
+
+ #[inline(always)]
+ fn remove<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> Option<V>
+ where K: Borrow<Q>
+ {
+ FxHashMap::remove(self, k)
+ }
+
+ #[inline(always)]
+ fn filter_map_collect<T>(&self, mut f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T> {
+ self.iter()
+ .filter_map(move |(k, v)| f(k, &*v))
+ .collect()
+ }
+
+ #[inline(always)]
+ fn get_or<E>(
+ &self,
+ k: K,
+ vacant: impl FnOnce() -> Result<V, E>
+ ) -> Result<&V, E>
+ {
+ match self.get(&k) {
+ Some(v) => Ok(v),
+ None => {
+ vacant()?;
+ bug!("The CTFE machine shouldn't ever need to extend the alloc_map when reading")
+ }
+ }
+ }
+
+ #[inline(always)]
+ fn get_mut_or<E>(
+ &mut self,
+ k: K,
+ vacant: impl FnOnce() -> Result<V, E>
+ ) -> Result<&mut V, E>
+ {
+ match self.entry(k) {
+ Entry::Occupied(e) => Ok(e.into_mut()),
+ Entry::Vacant(e) => {
+ let v = vacant()?;
+ Ok(e.insert(v))
+ }
+ }
+ }
+}
+
type CompileTimeEvalContext<'a, 'mir, 'tcx> =
EvalContext<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>;
{
type MemoryData = ();
type MemoryKinds = !;
+ type PointerTag = ();
+
+ type MemoryMap = FxHashMap<AllocId, (MemoryKind<!>, Allocation<()>)>;
- const MUT_STATIC_KIND: Option<!> = None; // no mutating of statics allowed
+ const STATIC_KIND: Option<!> = None; // no copying of statics allowed
+ const ENFORCE_VALIDITY: bool = false; // for now, we don't
fn find_fn(
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
fn find_foreign_static(
_tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
_def_id: DefId,
- ) -> EvalResult<'tcx, &'tcx Allocation> {
+ ) -> EvalResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag>>> {
err!(ReadForeignStatic)
}
+ #[inline(always)]
+ fn static_with_default_tag(
+ alloc: &'_ Allocation
+ ) -> Cow<'_, Allocation<Self::PointerTag>> {
+ // We do not use a tag so we can just cheaply forward the reference
+ Cow::Borrowed(alloc)
+ }
+
fn box_alloc(
_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
_dest: PlaceTy<'tcx>,
use hair::cx::Cx;
use hair::cx::block;
use hair::cx::to_ref::ToRef;
+use hair::util::UserAnnotatedTyHelpers;
use rustc::hir::def::{Def, CtorKind};
use rustc::mir::interpret::GlobalId;
use rustc::ty::{self, AdtKind, Ty};
adt_def: adt,
variant_index: 0,
substs,
- user_ty: user_annotated_ty_for_adt(cx, expr.hir_id, adt),
+ user_ty: cx.user_substs_applied_to_adt(expr.hir_id, adt),
fields: field_refs(cx, fields),
base: base.as_ref().map(|base| {
FruInfo {
adt_def: adt,
variant_index: index,
substs,
- user_ty: user_annotated_ty_for_adt(cx, expr.hir_id, adt),
+ user_ty: cx.user_substs_applied_to_adt(expr.hir_id, adt),
fields: field_refs(cx, fields),
base: None,
}
// user.
Def::StructCtor(_def_id, CtorKind::Const) |
Def::VariantCtor(_def_id, CtorKind::Const) =>
- match &cx.tables().node_id_to_type(hir_id).sty {
- ty::Adt(adt_def, _) => user_annotated_ty_for_adt(cx, hir_id, adt_def),
- sty => bug!("unexpected sty: {:?}", sty),
- },
+ cx.user_substs_applied_to_ty_of_hir_id(hir_id),
// `Self` is used in expression as a tuple struct constructor or an unit struct constructor
- Def::SelfCtor(_) => {
- let sty = &cx.tables().node_id_to_type(hir_id).sty;
- match sty {
- ty::FnDef(ref def_id, _) => {
- Some(cx.tables().user_substs(hir_id)?.unchecked_map(|user_substs| {
- // Here, we just pair a `DefId` with the
- // `user_substs`, so no new types etc are introduced.
- cx.tcx().mk_fn_def(*def_id, user_substs)
- }))
- }
- ty::Adt(ref adt_def, _) => {
- user_annotated_ty_for_adt(cx, hir_id, adt_def)
- }
- _ => {
- bug!("unexpected sty: {:?}", sty)
- }
- }
- }
+ Def::SelfCtor(_) =>
+ cx.user_substs_applied_to_ty_of_hir_id(hir_id),
+
_ =>
bug!("user_annotated_ty_for_def: unexpected def {:?} at {:?}", def, hir_id)
}
}
-fn user_annotated_ty_for_adt(
- cx: &mut Cx<'a, 'gcx, 'tcx>,
- hir_id: hir::HirId,
- adt_def: &'tcx AdtDef,
-) -> Option<CanonicalTy<'tcx>> {
- let user_substs = cx.tables().user_substs(hir_id)?;
- Some(user_substs.unchecked_map(|user_substs| {
- // Here, we just pair an `AdtDef` with the
- // `user_substs`, so no new types etc are introduced.
- cx.tcx().mk_adt(adt_def, user_substs)
- }))
-}
-
fn method_callee<'a, 'gcx, 'tcx>(
cx: &mut Cx<'a, 'gcx, 'tcx>,
expr: &hir::Expr,
adt_def,
variant_index: adt_def.variant_index_with_id(def_id),
substs,
- user_ty: user_annotated_ty_for_adt(cx, expr.hir_id, adt_def),
+ user_ty: cx.user_substs_applied_to_adt(expr.hir_id, adt_def),
fields: vec![],
base: None,
}
//!
use hair::*;
+use hair::util::UserAnnotatedTyHelpers;
use rustc_data_structures::indexed_vec::Idx;
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
}
}
+impl UserAnnotatedTyHelpers<'gcx, 'tcx> for Cx<'_, 'gcx, 'tcx> {
+ fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> {
+ self.tcx()
+ }
+
+ fn tables(&self) -> &ty::TypeckTables<'tcx> {
+ self.tables()
+ }
+}
+
fn lint_level_for_hir_id(tcx: TyCtxt, mut id: ast::NodeId) -> ast::NodeId {
// Right now we insert a `with_ignore` node in the dep graph here to
// ignore the fact that `lint_levels` below depends on the entire crate.
pub mod pattern;
pub use self::pattern::{BindingMode, Pattern, PatternKind, FieldPattern};
+mod util;
+
#[derive(Copy, Clone, Debug)]
pub enum LintLevel {
Inherited,
use const_eval::{const_field, const_variant_index};
+use hair::util::UserAnnotatedTyHelpers;
+
use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
use rustc::ty::{self, CanonicalTy, TyCtxt, AdtDef, Ty, Region};
field: Field::new(i),
pattern: self.lower_pattern(field),
})
- .collect();
- self.lower_variant_or_leaf(def, pat.span, ty, subpatterns)
+ .collect();
+
+ self.lower_variant_or_leaf(def, pat.hir_id, pat.span, ty, subpatterns)
}
PatKind::Struct(ref qpath, ref fields, _) => {
})
.collect();
- self.lower_variant_or_leaf(def, pat.span, ty, subpatterns)
+ self.lower_variant_or_leaf(def, pat.hir_id, pat.span, ty, subpatterns)
}
};
fn lower_variant_or_leaf(
&mut self,
def: Def,
+ hir_id: hir::HirId,
span: Span,
ty: Ty<'tcx>,
- subpatterns: Vec<FieldPattern<'tcx>>)
- -> PatternKind<'tcx>
- {
- match def {
+ subpatterns: Vec<FieldPattern<'tcx>>,
+ ) -> PatternKind<'tcx> {
+ let mut kind = match def {
Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => {
let enum_id = self.tcx.parent_def_id(variant_id).unwrap();
let adt_def = self.tcx.adt_def(enum_id);
self.errors.push(PatternError::NonConstPath(span));
PatternKind::Wild
}
+ };
+
+ if let Some(user_ty) = self.user_substs_applied_to_ty_of_hir_id(hir_id) {
+ let subpattern = Pattern {
+ span,
+ ty,
+ kind: Box::new(kind),
+ };
+
+ debug!("pattern user_ty = {:?} for pattern at {:?}", user_ty, span);
+
+ kind = PatternKind::AscribeUserType {
+ subpattern,
+ user_ty,
+ };
}
+
+ kind
}
/// Takes a HIR Path. If the path is a constant, evaluates it and feeds
},
}
}
- _ => self.lower_variant_or_leaf(def, span, ty, vec![]),
+ _ => self.lower_variant_or_leaf(def, id, span, ty, vec![]),
};
Pattern {
}
}
+impl UserAnnotatedTyHelpers<'tcx, 'tcx> for PatternContext<'_, 'tcx> {
+ fn tcx(&self) -> TyCtxt<'_, 'tcx, 'tcx> {
+ self.tcx
+ }
+
+ fn tables(&self) -> &ty::TypeckTables<'tcx> {
+ self.tables
+ }
+}
+
+
pub trait PatternFoldable<'tcx> : Sized {
fn fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
self.super_fold_with(folder)
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::hir;
+use rustc::ty::{self, AdtDef, CanonicalTy, TyCtxt};
+
+crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> {
+ fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx>;
+
+ fn tables(&self) -> &ty::TypeckTables<'tcx>;
+
+ fn user_substs_applied_to_adt(
+ &self,
+ hir_id: hir::HirId,
+ adt_def: &'tcx AdtDef,
+ ) -> Option<CanonicalTy<'tcx>> {
+ let user_substs = self.tables().user_substs(hir_id)?;
+ Some(user_substs.unchecked_map(|user_substs| {
+ // Here, we just pair an `AdtDef` with the
+ // `user_substs`, so no new types etc are introduced.
+ self.tcx().mk_adt(adt_def, user_substs)
+ }))
+ }
+
+ /// Looks up the type associated with this hir-id and applies the
+ /// user-given substitutions; the hir-id must map to a suitable
+ /// type.
+ fn user_substs_applied_to_ty_of_hir_id(&self, hir_id: hir::HirId) -> Option<CanonicalTy<'tcx>> {
+ let user_substs = self.tables().user_substs(hir_id)?;
+ match &self.tables().node_id_to_type(hir_id).sty {
+ ty::Adt(adt_def, _) => Some(user_substs.unchecked_map(|user_substs| {
+ // Ok to call `unchecked_map` because we just pair an
+ // `AdtDef` with the `user_substs`, so no new types
+ // etc are introduced.
+ self.tcx().mk_adt(adt_def, user_substs)
+ })),
+ ty::FnDef(def_id, _) => Some(user_substs.unchecked_map(|user_substs| {
+ // Here, we just pair a `DefId` with the
+ // `user_substs`, so no new types etc are introduced.
+ self.tcx().mk_fn_def(*def_id, user_substs)
+ })),
+ sty => bug!(
+ "sty: {:?} should not have user-substs {:?} recorded ",
+ sty,
+ user_substs
+ ),
+ }
+ }
+}
pub fn cast(
&mut self,
- src: OpTy<'tcx>,
+ src: OpTy<'tcx, M::PointerTag>,
kind: CastKind,
- dest: PlaceTy<'tcx>,
+ dest: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
let src_layout = src.layout;
let dst_layout = dest.layout;
pub(super) fn cast_scalar(
&self,
- val: Scalar,
+ val: Scalar<M::PointerTag>,
src_layout: TyLayout<'tcx>,
dest_layout: TyLayout<'tcx>,
- ) -> EvalResult<'tcx, Scalar> {
+ ) -> EvalResult<'tcx, Scalar<M::PointerTag>> {
use rustc::ty::TyKind::*;
trace!("Casting {:?}: {:?} to {:?}", val, src_layout.ty, dest_layout.ty);
v: u128,
src_layout: TyLayout<'tcx>,
dest_layout: TyLayout<'tcx>,
- ) -> EvalResult<'tcx, Scalar> {
+ ) -> EvalResult<'tcx, Scalar<M::PointerTag>> {
let signed = src_layout.abi.is_signed();
let v = if signed {
self.sign_extend(v, src_layout)
bits: u128,
fty: FloatTy,
dest_ty: Ty<'tcx>
- ) -> EvalResult<'tcx, Scalar> {
+ ) -> EvalResult<'tcx, Scalar<M::PointerTag>> {
use rustc::ty::TyKind::*;
use rustc_apfloat::FloatConvert;
match dest_ty.sty {
}
}
- fn cast_from_ptr(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Scalar> {
+ fn cast_from_ptr(
+ &self,
+ ptr: Pointer<M::PointerTag>,
+ ty: Ty<'tcx>
+ ) -> EvalResult<'tcx, Scalar<M::PointerTag>> {
use rustc::ty::TyKind::*;
match ty.sty {
// Casting to a reference or fn pointer is not permitted by rustc,
fn unsize_into_ptr(
&mut self,
- src: OpTy<'tcx>,
- dest: PlaceTy<'tcx>,
+ src: OpTy<'tcx, M::PointerTag>,
+ dest: PlaceTy<'tcx, M::PointerTag>,
// The pointee types
sty: Ty<'tcx>,
dty: Ty<'tcx>,
fn unsize_into(
&mut self,
- src: OpTy<'tcx>,
- dest: PlaceTy<'tcx>,
+ src: OpTy<'tcx, M::PointerTag>,
+ dest: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
match (&src.layout.ty.sty, &dest.layout.ty.sty) {
(&ty::Ref(_, s, _), &ty::Ref(_, d, _)) |
pub memory: Memory<'a, 'mir, 'tcx, M>,
/// The virtual call stack.
- pub(crate) stack: Vec<Frame<'mir, 'tcx>>,
+ pub(crate) stack: Vec<Frame<'mir, 'tcx, M::PointerTag>>,
}
/// A stack frame.
#[derive(Clone)]
-pub struct Frame<'mir, 'tcx: 'mir> {
+pub struct Frame<'mir, 'tcx: 'mir, Tag=()> {
////////////////////////////////////////////////////////////////////////////////
// Function and callsite information
////////////////////////////////////////////////////////////////////////////////
pub return_to_block: StackPopCleanup,
/// The location where the result of the current stack frame should be written to.
- pub return_place: Place,
+ pub return_place: Place<Tag>,
/// The list of locals for this stack frame, stored in order as
/// `[return_ptr, arguments..., variables..., temporaries...]`.
/// The locals are stored as `Option<Value>`s.
/// `None` represents a local that is currently dead, while a live local
/// can either directly contain `Scalar` or refer to some part of an `Allocation`.
- pub locals: IndexVec<mir::Local, LocalValue<AllocId>>,
+ pub locals: IndexVec<mir::Local, LocalValue<Tag>>,
////////////////////////////////////////////////////////////////////////////////
// Current position within the function
// State of a local variable
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
-pub enum LocalValue<Id=AllocId> {
+pub enum LocalValue<Tag=(), Id=AllocId> {
Dead,
// Mostly for convenience, we re-use the `Operand` type here.
// This is an optimization over just always having a pointer here;
// we can thus avoid doing an allocation when the local just stores
// immediate values *and* never has its address taken.
- Live(Operand<Id>),
+ Live(Operand<Tag, Id>),
}
-impl<'tcx> LocalValue {
- pub fn access(&self) -> EvalResult<'tcx, &Operand> {
+impl<'tcx, Tag> LocalValue<Tag> {
+ pub fn access(&self) -> EvalResult<'tcx, &Operand<Tag>> {
match self {
LocalValue::Dead => err!(DeadLocal),
LocalValue::Live(ref val) => Ok(val),
}
}
- pub fn access_mut(&mut self) -> EvalResult<'tcx, &mut Operand> {
+ pub fn access_mut(&mut self) -> EvalResult<'tcx, &mut Operand<Tag>> {
match self {
LocalValue::Dead => err!(DeadLocal),
LocalValue::Live(ref mut val) => Ok(val),
&mut self.memory
}
- pub fn stack(&self) -> &[Frame<'mir, 'tcx>] {
+ pub fn stack(&self) -> &[Frame<'mir, 'tcx, M::PointerTag>] {
&self.stack
}
/// Mark a storage as live, killing the previous content and returning it.
/// Remember to deallocate that!
- pub fn storage_live(&mut self, local: mir::Local) -> EvalResult<'tcx, LocalValue> {
+ pub fn storage_live(
+ &mut self,
+ local: mir::Local
+ ) -> EvalResult<'tcx, LocalValue<M::PointerTag>> {
+ assert!(local != mir::RETURN_PLACE, "Cannot make return place live");
trace!("{:?} is now live", local);
let layout = self.layout_of_local(self.cur_frame(), local)?;
/// Returns the old value of the local.
/// Remember to deallocate that!
- pub fn storage_dead(&mut self, local: mir::Local) -> LocalValue {
+ pub fn storage_dead(&mut self, local: mir::Local) -> LocalValue<M::PointerTag> {
+ assert!(local != mir::RETURN_PLACE, "Cannot make return place dead");
trace!("{:?} is now dead", local);
mem::replace(&mut self.frame_mut().locals[local], LocalValue::Dead)
}
- pub fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
+ pub fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value<M::PointerTag>> {
let ptr = self.memory.allocate_static_bytes(s.as_bytes());
Ok(Value::new_slice(Scalar::Ptr(ptr), s.len() as u64, self.tcx.tcx))
}
}
/// Return the actual dynamic size and alignment of the place at the given type.
- /// Only the "extra" (metadata) part of the place matters.
+ /// Only the `meta` part of the place matters.
pub(super) fn size_and_align_of(
&self,
- metadata: Option<Scalar>,
+ metadata: Option<Scalar<M::PointerTag>>,
layout: TyLayout<'tcx>,
) -> EvalResult<'tcx, (Size, Align)> {
let metadata = match metadata {
#[inline]
pub fn size_and_align_of_mplace(
&self,
- mplace: MPlaceTy<'tcx>
+ mplace: MPlaceTy<'tcx, M::PointerTag>
) -> EvalResult<'tcx, (Size, Align)> {
- self.size_and_align_of(mplace.extra, mplace.layout)
+ self.size_and_align_of(mplace.meta, mplace.layout)
}
pub fn push_stack_frame(
instance: ty::Instance<'tcx>,
span: source_map::Span,
mir: &'mir mir::Mir<'tcx>,
- return_place: Place,
+ return_place: Place<M::PointerTag>,
return_to_block: StackPopCleanup,
) -> EvalResult<'tcx> {
::log_settings::settings().indentation += 1;
let dummy =
LocalValue::Live(Operand::Immediate(Value::Scalar(ScalarMaybeUndef::Undef)));
let mut locals = IndexVec::from_elem(dummy, &mir.local_decls);
+ // Return place is handled specially by the `eval_place` functions, and the
+ // entry in `locals` should never be used. Make it dead, to be sure.
+ locals[mir::RETURN_PLACE] = LocalValue::Dead;
// Now mark those locals as dead that we do not want to initialize
match self.tcx.describe_def(instance.def_id()) {
// statics and constants don't have `Storage*` statements, no need to look for them
Ok(())
}
- pub(super) fn deallocate_local(&mut self, local: LocalValue) -> EvalResult<'tcx> {
+ pub(super) fn deallocate_local(
+ &mut self,
+ local: LocalValue<M::PointerTag>,
+ ) -> EvalResult<'tcx> {
// FIXME: should we tell the user that there was a local which was never written to?
if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
trace!("deallocating local");
}
#[inline(always)]
- pub fn frame(&self) -> &Frame<'mir, 'tcx> {
+ pub fn frame(&self) -> &Frame<'mir, 'tcx, M::PointerTag> {
self.stack.last().expect("no call frames exist")
}
#[inline(always)]
- pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx> {
+ pub fn frame_mut(&mut self) -> &mut Frame<'mir, 'tcx, M::PointerTag> {
self.stack.last_mut().expect("no call frames exist")
}
}
}
- pub fn dump_place(&self, place: Place) {
+ pub fn dump_place(&self, place: Place<M::PointerTag>) {
// Debug output
if !log_enabled!(::log::Level::Trace) {
return;
};
-fn numeric_intrinsic<'tcx>(
+fn numeric_intrinsic<'tcx, Tag>(
name: &str,
bits: u128,
kind: Primitive,
-) -> EvalResult<'tcx, Scalar> {
+) -> EvalResult<'tcx, Scalar<Tag>> {
let size = match kind {
Primitive::Int(integer, _) => integer.size(),
_ => bug!("invalid `{}` argument: {:?}", name, bits),
pub fn emulate_intrinsic(
&mut self,
instance: ty::Instance<'tcx>,
- args: &[OpTy<'tcx>],
- dest: PlaceTy<'tcx>,
+ args: &[OpTy<'tcx, M::PointerTag>],
+ dest: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx, bool> {
let substs = instance.substs;
pub fn hook_fn(
&mut self,
instance: ty::Instance<'tcx>,
- args: &[OpTy<'tcx>],
- dest: Option<PlaceTy<'tcx>>,
+ args: &[OpTy<'tcx, M::PointerTag>],
+ dest: Option<PlaceTy<'tcx, M::PointerTag>>,
) -> EvalResult<'tcx, bool> {
let def_id = instance.def_id();
// Some fn calls are actually BinOp intrinsics
//! This separation exists to ensure that no fancy miri features like
//! interpreting common C functions leak into CTFE.
+use std::borrow::{Borrow, Cow};
+use std::hash::Hash;
+
use rustc::hir::def_id::DefId;
-use rustc::mir::interpret::{Allocation, EvalResult, Scalar};
+use rustc::mir::interpret::{Allocation, AllocId, EvalResult, Scalar};
use rustc::mir;
use rustc::ty::{self, layout::TyLayout, query::TyCtxtAt};
-use super::{EvalContext, PlaceTy, OpTy};
+use super::{EvalContext, PlaceTy, OpTy, MemoryKind};
+
+/// The functionality needed by memory to manage its allocations
+pub trait AllocMap<K: Hash + Eq, V> {
+ /// Test if the map contains the given key.
+ /// Deliberately takes `&mut` because that is sufficient, and some implementations
+ /// can be more efficient then (using `RefCell::get_mut`).
+ fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool
+ where K: Borrow<Q>;
+
+ /// Insert new entry into the map.
+ fn insert(&mut self, k: K, v: V) -> Option<V>;
+
+ /// Remove entry from the map.
+ fn remove<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> Option<V>
+ where K: Borrow<Q>;
+
+ /// Return data based the keys and values in the map.
+ fn filter_map_collect<T>(&self, f: impl FnMut(&K, &V) -> Option<T>) -> Vec<T>;
+
+ /// Return a reference to entry `k`. If no such entry exists, call
+ /// `vacant` and either forward its error, or add its result to the map
+ /// and return a reference to *that*.
+ fn get_or<E>(
+ &self,
+ k: K,
+ vacant: impl FnOnce() -> Result<V, E>
+ ) -> Result<&V, E>;
+
+ /// Return a mutable reference to entry `k`. If no such entry exists, call
+ /// `vacant` and either forward its error, or add its result to the map
+ /// and return a reference to *that*.
+ fn get_mut_or<E>(
+ &mut self,
+ k: K,
+ vacant: impl FnOnce() -> Result<V, E>
+ ) -> Result<&mut V, E>;
+}
/// Methods of this trait signifies a point where CTFE evaluation would fail
/// and some use case dependent behaviour can instead be applied.
-/// FIXME: We should be able to get rid of the 'a here if we can get rid of the 'a in
-/// `snapshot::EvalSnapshot`.
pub trait Machine<'a, 'mir, 'tcx>: Sized {
/// Additional data that can be accessed via the Memory
type MemoryData;
/// Additional memory kinds a machine wishes to distinguish from the builtin ones
type MemoryKinds: ::std::fmt::Debug + Copy + Eq;
- /// The memory kind to use for mutated statics -- or None if those are not supported.
- const MUT_STATIC_KIND: Option<Self::MemoryKinds>;
+ /// Memory's allocation map
+ type MemoryMap:
+ AllocMap<AllocId, (MemoryKind<Self::MemoryKinds>, Allocation<Self::PointerTag>)> +
+ Default +
+ Clone;
+
+ /// Tag tracked alongside every pointer. This is inert for now, in preparation for
+ /// a future implementation of "Stacked Borrows"
+ /// <https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html>.
+ type PointerTag: ::std::fmt::Debug + Default + Copy + Eq + Hash + 'static;
+
+ /// The memory kind to use for copied statics -- or None if those are not supported.
+ /// Statics are copied under two circumstances: When they are mutated, and when
+ /// `static_with_default_tag` or `find_foreign_static` (see below) returns an owned allocation
+ /// that is added to the memory so that the work is not done twice.
+ const STATIC_KIND: Option<Self::MemoryKinds>;
+
+ /// Whether to enforce the validity invariant
+ const ENFORCE_VALIDITY: bool;
/// Called before a basic block terminator is executed.
/// You can use this to detect endlessly running programs.
fn find_fn(
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
instance: ty::Instance<'tcx>,
- args: &[OpTy<'tcx>],
- dest: Option<PlaceTy<'tcx>>,
+ args: &[OpTy<'tcx, Self::PointerTag>],
+ dest: Option<PlaceTy<'tcx, Self::PointerTag>>,
ret: Option<mir::BasicBlock>,
) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>>;
fn call_intrinsic(
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
instance: ty::Instance<'tcx>,
- args: &[OpTy<'tcx>],
- dest: PlaceTy<'tcx>,
+ args: &[OpTy<'tcx, Self::PointerTag>],
+ dest: PlaceTy<'tcx, Self::PointerTag>,
) -> EvalResult<'tcx>;
/// Called for read access to a foreign static item.
- /// This can be called multiple times for the same static item and should return consistent
- /// results. Once the item is *written* the first time, as usual for statics a copy is
- /// made and this function is not called again.
+ ///
+ /// This will only be called once per static and machine; the result is cached in
+ /// the machine memory. (This relies on `AllocMap::get_or` being able to add the
+ /// owned allocation to the map even when the map is shared.)
fn find_foreign_static(
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
def_id: DefId,
- ) -> EvalResult<'tcx, &'tcx Allocation>;
+ ) -> EvalResult<'tcx, Cow<'tcx, Allocation<Self::PointerTag>>>;
+
+ /// Called to turn an allocation obtained from the `tcx` into one that has
+ /// the appropriate tags on each pointer.
+ ///
+ /// This should avoid copying if no work has to be done! If this returns an owned
+ /// allocation (because a copy had to be done to add the tags), machine memory will
+ /// cache the result. (This relies on `AllocMap::get_or` being able to add the
+ /// owned allocation to the map even when the map is shared.)
+ fn static_with_default_tag(
+ alloc: &'_ Allocation
+ ) -> Cow<'_, Allocation<Self::PointerTag>>;
/// Called for all binary operations on integer(-like) types when one operand is a pointer
/// value, and for the `Offset` operation that is inherently about pointers.
fn ptr_op(
ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
bin_op: mir::BinOp,
- left: Scalar,
+ left: Scalar<Self::PointerTag>,
left_layout: TyLayout<'tcx>,
- right: Scalar,
+ right: Scalar<Self::PointerTag>,
right_layout: TyLayout<'tcx>,
- ) -> EvalResult<'tcx, (Scalar, bool)>;
+ ) -> EvalResult<'tcx, (Scalar<Self::PointerTag>, bool)>;
/// Heap allocations via the `box` keyword
///
/// Returns a pointer to the allocated memory
fn box_alloc(
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
- dest: PlaceTy<'tcx>,
+ dest: PlaceTy<'tcx, Self::PointerTag>,
) -> EvalResult<'tcx>;
/// Execute a validation operation
use std::collections::VecDeque;
use std::ptr;
+use std::borrow::Cow;
-use rustc::ty::{self, Instance, query::TyCtxtAt};
+use rustc::ty::{self, Instance, ParamEnv, query::TyCtxtAt};
use rustc::ty::layout::{self, Align, TargetDataLayout, Size, HasDataLayout};
-use rustc::mir::interpret::{Pointer, AllocId, Allocation, ConstValue, GlobalId,
- EvalResult, Scalar, EvalErrorKind, AllocType, PointerArithmetic,
- truncate};
+use rustc::mir::interpret::{
+ Pointer, AllocId, Allocation, ConstValue, GlobalId,
+ EvalResult, Scalar, EvalErrorKind, AllocType, PointerArithmetic,
+ truncate
+};
pub use rustc::mir::interpret::{write_target_uint, read_target_uint};
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
use syntax::ast::Mutability;
-use super::{Machine, ScalarMaybeUndef};
+use super::{Machine, AllocMap, ScalarMaybeUndef};
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
pub enum MemoryKind<T> {
/// Error if deallocated except during a stack pop
Stack,
+ /// Error if ever deallocated
+ Vtable,
/// Additional memory kinds a machine wishes to distinguish from the builtin ones
Machine(T),
}
/// Allocations local to this instance of the miri engine. The kind
/// helps ensure that the same mechanism is used for allocation and
/// deallocation. When an allocation is not found here, it is a
- /// static and looked up in the `tcx` for read access. Writing to
- /// a static creates a copy here, in the machine.
- alloc_map: FxHashMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation)>,
+ /// static and looked up in the `tcx` for read access. Some machines may
+ /// have to mutate this map even on a read-only access to a static (because
+ /// they do pointer provenance tracking and the allocations in `tcx` have
+ /// the wrong type), so we let the machine override this type.
+ /// Either way, if the machine allows writing to a static, doing so will
+ /// create a copy of the static allocation here.
+ alloc_map: M::MemoryMap,
/// To be able to compare pointers with NULL, and to check alignment for accesses
/// to ZSTs (where pointers may dangle), we keep track of the size even for allocations
pub fn new(tcx: TyCtxtAt<'a, 'tcx, 'tcx>, data: M::MemoryData) -> Self {
Memory {
data,
- alloc_map: FxHashMap::default(),
+ alloc_map: Default::default(),
dead_alloc_map: FxHashMap::default(),
tcx,
}
}
- pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> Pointer {
- self.tcx.alloc_map.lock().create_fn_alloc(instance).into()
+ pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> Pointer<M::PointerTag> {
+ Pointer::from(self.tcx.alloc_map.lock().create_fn_alloc(instance)).with_default_tag()
}
- pub fn allocate_static_bytes(&mut self, bytes: &[u8]) -> Pointer {
- self.tcx.allocate_bytes(bytes).into()
+ pub fn allocate_static_bytes(&mut self, bytes: &[u8]) -> Pointer<M::PointerTag> {
+ Pointer::from(self.tcx.allocate_bytes(bytes)).with_default_tag()
}
pub fn allocate_with(
&mut self,
- alloc: Allocation,
+ alloc: Allocation<M::PointerTag>,
kind: MemoryKind<M::MemoryKinds>,
) -> EvalResult<'tcx, AllocId> {
let id = self.tcx.alloc_map.lock().reserve();
size: Size,
align: Align,
kind: MemoryKind<M::MemoryKinds>,
- ) -> EvalResult<'tcx, Pointer> {
- self.allocate_with(Allocation::undef(size, align), kind).map(Pointer::from)
+ ) -> EvalResult<'tcx, Pointer<M::PointerTag>> {
+ let ptr = Pointer::from(self.allocate_with(Allocation::undef(size, align), kind)?);
+ Ok(ptr.with_default_tag())
}
pub fn reallocate(
&mut self,
- ptr: Pointer,
+ ptr: Pointer<M::PointerTag>,
old_size: Size,
old_align: Align,
new_size: Size,
new_align: Align,
kind: MemoryKind<M::MemoryKinds>,
- ) -> EvalResult<'tcx, Pointer> {
+ ) -> EvalResult<'tcx, Pointer<M::PointerTag>> {
if ptr.offset.bytes() != 0 {
return err!(ReallocateNonBasePtr);
}
}
/// Deallocate a local, or do nothing if that local has been made into a static
- pub fn deallocate_local(&mut self, ptr: Pointer) -> EvalResult<'tcx> {
+ pub fn deallocate_local(&mut self, ptr: Pointer<M::PointerTag>) -> EvalResult<'tcx> {
// The allocation might be already removed by static interning.
// This can only really happen in the CTFE instance, not in miri.
if self.alloc_map.contains_key(&ptr.alloc_id) {
pub fn deallocate(
&mut self,
- ptr: Pointer,
+ ptr: Pointer<M::PointerTag>,
size_and_align: Option<(Size, Align)>,
kind: MemoryKind<M::MemoryKinds>,
) -> EvalResult<'tcx> {
/// Check that the pointer is aligned AND non-NULL. This supports ZSTs in two ways:
/// You can pass a scalar, and a `Pointer` does not have to actually still be allocated.
- pub fn check_align(&self, ptr: Scalar, required_align: Align) -> EvalResult<'tcx> {
+ pub fn check_align(
+ &self,
+ ptr: Scalar<M::PointerTag>,
+ required_align: Align
+ ) -> EvalResult<'tcx> {
// Check non-NULL/Undef, extract offset
let (offset, alloc_align) = match ptr {
Scalar::Ptr(ptr) => {
- let (size, align) = self.get_size_and_align(ptr.alloc_id)?;
+ let (size, align) = self.get_size_and_align(ptr.alloc_id);
// check this is not NULL -- which we can ensure only if this is in-bounds
// of some (potentially dead) allocation.
if ptr.offset > size {
return err!(PointerOutOfBounds {
- ptr,
+ ptr: ptr.erase_tag(),
access: true,
allocation_size: size,
});
/// If you want to check bounds before doing a memory access, be sure to
/// check the pointer one past the end of your access, then everything will
/// work out exactly.
- pub fn check_bounds(&self, ptr: Pointer, access: bool) -> EvalResult<'tcx> {
+ pub fn check_bounds_ptr(&self, ptr: Pointer<M::PointerTag>, access: bool) -> EvalResult<'tcx> {
let alloc = self.get(ptr.alloc_id)?;
let allocation_size = alloc.bytes.len() as u64;
if ptr.offset.bytes() > allocation_size {
return err!(PointerOutOfBounds {
- ptr,
+ ptr: ptr.erase_tag(),
access,
allocation_size: Size::from_bytes(allocation_size),
});
}
Ok(())
}
+
+ /// Check if the memory range beginning at `ptr` and of size `Size` is "in-bounds".
+ #[inline(always)]
+ pub fn check_bounds(
+ &self,
+ ptr: Pointer<M::PointerTag>,
+ size: Size,
+ access: bool
+ ) -> EvalResult<'tcx> {
+ // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
+ self.check_bounds_ptr(ptr.offset(size, &*self)?, access)
+ }
}
/// Allocation accessors
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
- /// Helper function to obtain the global (tcx) allocation for a static
+ /// Helper function to obtain the global (tcx) allocation for a static.
+ /// This attempts to return a reference to an existing allocation if
+ /// one can be found in `tcx`. That, however, is only possible if `tcx` and
+ /// this machine use the same pointer tag, so it is indirected through
+ /// `M::static_with_default_tag`.
fn get_static_alloc(
tcx: TyCtxtAt<'a, 'tcx, 'tcx>,
id: AllocId,
- ) -> EvalResult<'tcx, &'tcx Allocation> {
+ ) -> EvalResult<'tcx, Cow<'tcx, Allocation<M::PointerTag>>> {
let alloc = tcx.alloc_map.lock().get(id);
let def_id = match alloc {
Some(AllocType::Memory(mem)) => {
- return Ok(mem)
+ // We got tcx memory. Let the machine figure out whether and how to
+ // turn that into memory with the right pointer tag.
+ return Ok(M::static_with_default_tag(mem))
}
Some(AllocType::Function(..)) => {
return err!(DerefFunctionPointer)
EvalErrorKind::ReferencedConstant(err).into()
}).map(|const_val| {
if let ConstValue::ByRef(_, allocation, _) = const_val.val {
- allocation
+ // We got tcx memory. Let the machine figure out whether and how to
+ // turn that into memory with the right pointer tag.
+ M::static_with_default_tag(allocation)
} else {
bug!("Matching on non-ByRef static")
}
})
}
- pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
- match self.alloc_map.get(&id) {
- // Normal alloc?
- Some(alloc) => Ok(&alloc.1),
- // Static. No need to make any copies, just provide read access to the global static
- // memory in tcx.
- None => Self::get_static_alloc(self.tcx, id),
- }
- }
-
- pub fn get_size_and_align(&self, id: AllocId) -> EvalResult<'tcx, (Size, Align)> {
- Ok(match self.get(id) {
- Ok(alloc) => (Size::from_bytes(alloc.bytes.len() as u64), alloc.align),
- Err(err) => match err.kind {
- EvalErrorKind::DanglingPointerDeref =>
- // This should be in the dead allocation map
- *self.dead_alloc_map.get(&id).expect(
- "allocation missing in dead_alloc_map"
- ),
- // E.g. a function ptr allocation
- _ => return Err(err)
+ pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation<M::PointerTag>> {
+ // The error type of the inner closure here is somewhat funny. We have two
+ // ways of "erroring": An actual error, or because we got a reference from
+ // `get_static_alloc` that we can actually use directly without inserting anything anywhere.
+ // So the error type is `EvalResult<'tcx, &Allocation<M::PointerTag>>`.
+ let a = self.alloc_map.get_or(id, || {
+ let alloc = Self::get_static_alloc(self.tcx, id).map_err(Err)?;
+ match alloc {
+ Cow::Borrowed(alloc) => {
+ // We got a ref, cheaply return that as an "error" so that the
+ // map does not get mutated.
+ Err(Ok(alloc))
+ }
+ Cow::Owned(alloc) => {
+ // Need to put it into the map and return a ref to that
+ let kind = M::STATIC_KIND.expect(
+ "I got an owned allocation that I have to copy but the machine does \
+ not expect that to happen"
+ );
+ Ok((MemoryKind::Machine(kind), alloc))
+ }
}
- })
+ });
+ // Now unpack that funny error type
+ match a {
+ Ok(a) => Ok(&a.1),
+ Err(a) => a
+ }
}
pub fn get_mut(
&mut self,
id: AllocId,
- ) -> EvalResult<'tcx, &mut Allocation> {
- // Static?
- if !self.alloc_map.contains_key(&id) {
- // Ask the machine for what to do
- if let Some(kind) = M::MUT_STATIC_KIND {
- // The machine supports mutating statics. Make a copy, use that.
- self.deep_copy_static(id, MemoryKind::Machine(kind))?;
- } else {
- return err!(ModifiedConstantMemory)
+ ) -> EvalResult<'tcx, &mut Allocation<M::PointerTag>> {
+ let tcx = self.tcx;
+ let a = self.alloc_map.get_mut_or(id, || {
+ // Need to make a copy, even if `get_static_alloc` is able
+ // to give us a cheap reference.
+ let alloc = Self::get_static_alloc(tcx, id)?;
+ if alloc.mutability == Mutability::Immutable {
+ return err!(ModifiedConstantMemory);
+ }
+ let kind = M::STATIC_KIND.expect(
+ "An allocation is being mutated but the machine does not expect that to happen"
+ );
+ Ok((MemoryKind::Machine(kind), alloc.into_owned()))
+ });
+ // Unpack the error type manually because type inference doesn't
+ // work otherwise (and we cannot help it because `impl Trait`)
+ match a {
+ Err(e) => Err(e),
+ Ok(a) => {
+ let a = &mut a.1;
+ if a.mutability == Mutability::Immutable {
+ return err!(ModifiedConstantMemory);
+ }
+ Ok(a)
}
}
- // If we come here, we know the allocation is in our map
- let alloc = &mut self.alloc_map.get_mut(&id).unwrap().1;
- // See if we are allowed to mutate this
- if alloc.mutability == Mutability::Immutable {
- err!(ModifiedConstantMemory)
- } else {
- Ok(alloc)
+ }
+
+ pub fn get_size_and_align(&self, id: AllocId) -> (Size, Align) {
+ if let Ok(alloc) = self.get(id) {
+ return (Size::from_bytes(alloc.bytes.len() as u64), alloc.align);
+ }
+ // Could also be a fn ptr or extern static
+ match self.tcx.alloc_map.lock().get(id) {
+ Some(AllocType::Function(..)) => (Size::ZERO, Align::from_bytes(1, 1).unwrap()),
+ Some(AllocType::Static(did)) => {
+ // The only way `get` couldn't have worked here is if this is an extern static
+ assert!(self.tcx.is_foreign_item(did));
+ // Use size and align of the type
+ let ty = self.tcx.type_of(did);
+ let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();
+ (layout.size, layout.align)
+ }
+ _ => {
+ // Must be a deallocated pointer
+ *self.dead_alloc_map.get(&id).expect(
+ "allocation missing in dead_alloc_map"
+ )
+ }
}
}
- pub fn get_fn(&self, ptr: Pointer) -> EvalResult<'tcx, Instance<'tcx>> {
+ pub fn get_fn(&self, ptr: Pointer<M::PointerTag>) -> EvalResult<'tcx, Instance<'tcx>> {
if ptr.offset.bytes() != 0 {
return err!(InvalidFunctionPointer);
}
}
}
+ pub fn mark_immutable(&mut self, id: AllocId) -> EvalResult<'tcx> {
+ self.get_mut(id)?.mutability = Mutability::Immutable;
+ Ok(())
+ }
+
/// For debugging, print an allocation and all allocations it points to, recursively.
pub fn dump_alloc(&self, id: AllocId) {
- if !log_enabled!(::log::Level::Trace) {
- return;
- }
self.dump_allocs(vec![id]);
}
+ fn dump_alloc_helper<Tag>(
+ &self,
+ allocs_seen: &mut FxHashSet<AllocId>,
+ allocs_to_print: &mut VecDeque<AllocId>,
+ mut msg: String,
+ alloc: &Allocation<Tag>,
+ extra: String,
+ ) {
+ use std::fmt::Write;
+
+ let prefix_len = msg.len();
+ let mut relocations = vec![];
+
+ for i in 0..(alloc.bytes.len() as u64) {
+ let i = Size::from_bytes(i);
+ if let Some(&(_, target_id)) = alloc.relocations.get(&i) {
+ if allocs_seen.insert(target_id) {
+ allocs_to_print.push_back(target_id);
+ }
+ relocations.push((i, target_id));
+ }
+ if alloc.undef_mask.is_range_defined(i, i + Size::from_bytes(1)).is_ok() {
+ // this `as usize` is fine, since `i` came from a `usize`
+ write!(msg, "{:02x} ", alloc.bytes[i.bytes() as usize]).unwrap();
+ } else {
+ msg.push_str("__ ");
+ }
+ }
+
+ trace!(
+ "{}({} bytes, alignment {}){}",
+ msg,
+ alloc.bytes.len(),
+ alloc.align.abi(),
+ extra
+ );
+
+ if !relocations.is_empty() {
+ msg.clear();
+ write!(msg, "{:1$}", "", prefix_len).unwrap(); // Print spaces.
+ let mut pos = Size::ZERO;
+ let relocation_width = (self.pointer_size().bytes() - 1) * 3;
+ for (i, target_id) in relocations {
+ // this `as usize` is fine, since we can't print more chars than `usize::MAX`
+ write!(msg, "{:1$}", "", ((i - pos) * 3).bytes() as usize).unwrap();
+ let target = format!("({})", target_id);
+ // this `as usize` is fine, since we can't print more chars than `usize::MAX`
+ write!(msg, "└{0:─^1$}┘ ", target, relocation_width as usize).unwrap();
+ pos = i + self.pointer_size();
+ }
+ trace!("{}", msg);
+ }
+ }
+
/// For debugging, print a list of allocations and all allocations they point to, recursively.
pub fn dump_allocs(&self, mut allocs: Vec<AllocId>) {
if !log_enabled!(::log::Level::Trace) {
return;
}
- use std::fmt::Write;
allocs.sort();
allocs.dedup();
let mut allocs_to_print = VecDeque::from(allocs);
let mut allocs_seen = FxHashSet::default();
while let Some(id) = allocs_to_print.pop_front() {
- let mut msg = format!("Alloc {:<5} ", format!("{}:", id));
- let prefix_len = msg.len();
- let mut relocations = vec![];
-
- let (alloc, immutable) =
- // normal alloc?
- match self.alloc_map.get(&id) {
- Some((kind, alloc)) => (alloc, match kind {
+ let msg = format!("Alloc {:<5} ", format!("{}:", id));
+
+ // normal alloc?
+ match self.alloc_map.get_or(id, || Err(())) {
+ Ok((kind, alloc)) => {
+ let extra = match kind {
MemoryKind::Stack => " (stack)".to_owned(),
+ MemoryKind::Vtable => " (vtable)".to_owned(),
MemoryKind::Machine(m) => format!(" ({:?})", m),
- }),
- None => {
- // static alloc?
- match self.tcx.alloc_map.lock().get(id) {
- Some(AllocType::Memory(a)) => (a, " (immutable)".to_owned()),
- Some(AllocType::Function(func)) => {
- trace!("{} {}", msg, func);
- continue;
- }
- Some(AllocType::Static(did)) => {
- trace!("{} {:?}", msg, did);
- continue;
- }
- None => {
- trace!("{} (deallocated)", msg);
- continue;
- }
+ };
+ self.dump_alloc_helper(
+ &mut allocs_seen, &mut allocs_to_print,
+ msg, alloc, extra
+ );
+ },
+ Err(()) => {
+ // static alloc?
+ match self.tcx.alloc_map.lock().get(id) {
+ Some(AllocType::Memory(alloc)) => {
+ self.dump_alloc_helper(
+ &mut allocs_seen, &mut allocs_to_print,
+ msg, alloc, " (immutable)".to_owned()
+ );
+ }
+ Some(AllocType::Function(func)) => {
+ trace!("{} {}", msg, func);
+ }
+ Some(AllocType::Static(did)) => {
+ trace!("{} {:?}", msg, did);
+ }
+ None => {
+ trace!("{} (deallocated)", msg);
}
- },
- };
-
- for i in 0..(alloc.bytes.len() as u64) {
- let i = Size::from_bytes(i);
- if let Some(&target_id) = alloc.relocations.get(&i) {
- if allocs_seen.insert(target_id) {
- allocs_to_print.push_back(target_id);
}
- relocations.push((i, target_id));
- }
- if alloc.undef_mask.is_range_defined(i, i + Size::from_bytes(1)).is_ok() {
- // this `as usize` is fine, since `i` came from a `usize`
- write!(msg, "{:02x} ", alloc.bytes[i.bytes() as usize]).unwrap();
- } else {
- msg.push_str("__ ");
- }
- }
+ },
+ };
- trace!(
- "{}({} bytes, alignment {}){}",
- msg,
- alloc.bytes.len(),
- alloc.align.abi(),
- immutable
- );
-
- if !relocations.is_empty() {
- msg.clear();
- write!(msg, "{:1$}", "", prefix_len).unwrap(); // Print spaces.
- let mut pos = Size::ZERO;
- let relocation_width = (self.pointer_size().bytes() - 1) * 3;
- for (i, target_id) in relocations {
- // this `as usize` is fine, since we can't print more chars than `usize::MAX`
- write!(msg, "{:1$}", "", ((i - pos) * 3).bytes() as usize).unwrap();
- let target = format!("({})", target_id);
- // this `as usize` is fine, since we can't print more chars than `usize::MAX`
- write!(msg, "└{0:─^1$}┘ ", target, relocation_width as usize).unwrap();
- pos = i + self.pointer_size();
- }
- trace!("{}", msg);
- }
}
}
pub fn leak_report(&self) -> usize {
trace!("### LEAK REPORT ###");
- let mut_static_kind = M::MUT_STATIC_KIND.map(|k| MemoryKind::Machine(k));
- let leaks: Vec<_> = self.alloc_map
- .iter()
- .filter_map(|(&id, &(kind, _))|
- // exclude mutable statics
- if Some(kind) == mut_static_kind { None } else { Some(id) } )
- .collect();
+ let leaks: Vec<_> = self.alloc_map.filter_map_collect(|&id, &(kind, _)| {
+ // exclude statics and vtables
+ let exclude = match kind {
+ MemoryKind::Stack => false,
+ MemoryKind::Vtable => true,
+ MemoryKind::Machine(k) => Some(k) == M::STATIC_KIND,
+ };
+ if exclude { None } else { Some(id) }
+ });
let n = leaks.len();
self.dump_allocs(leaks);
n
/// The last argument controls whether we error out when there are undefined
/// or pointer bytes. You should never call this, call `get_bytes` or
/// `get_bytes_with_undef_and_ptr` instead,
+ ///
+ /// This function also guarantees that the resulting pointer will remain stable
+ /// even when new allocations are pushed to the `HashMap`. `copy_repeatedly` relies
+ /// on that.
fn get_bytes_internal(
&self,
- ptr: Pointer,
+ ptr: Pointer<M::PointerTag>,
size: Size,
align: Align,
check_defined_and_ptr: bool,
) -> EvalResult<'tcx, &[u8]> {
assert_ne!(size.bytes(), 0, "0-sized accesses should never even get a `Pointer`");
self.check_align(ptr.into(), align)?;
- // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
- self.check_bounds(ptr.offset(size, &*self)?, true)?;
+ self.check_bounds(ptr, size, true)?;
if check_defined_and_ptr {
self.check_defined(ptr, size)?;
}
#[inline]
- fn get_bytes(&self, ptr: Pointer, size: Size, align: Align) -> EvalResult<'tcx, &[u8]> {
+ fn get_bytes(
+ &self,
+ ptr: Pointer<M::PointerTag>,
+ size: Size,
+ align: Align
+ ) -> EvalResult<'tcx, &[u8]> {
self.get_bytes_internal(ptr, size, align, true)
}
#[inline]
fn get_bytes_with_undef_and_ptr(
&self,
- ptr: Pointer,
+ ptr: Pointer<M::PointerTag>,
size: Size,
align: Align
) -> EvalResult<'tcx, &[u8]> {
/// so be sure to actually put data there!
fn get_bytes_mut(
&mut self,
- ptr: Pointer,
+ ptr: Pointer<M::PointerTag>,
size: Size,
align: Align,
) -> EvalResult<'tcx, &mut [u8]> {
assert_ne!(size.bytes(), 0, "0-sized accesses should never even get a `Pointer`");
self.check_align(ptr.into(), align)?;
- // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow)
- self.check_bounds(ptr.offset(size, &self)?, true)?;
+ self.check_bounds(ptr, size, true)?;
self.mark_definedness(ptr, size, true)?;
self.clear_relocations(ptr, size)?;
}
}
-/// Reading and writing
-impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
+/// Interning (for CTFE)
+impl<'a, 'mir, 'tcx, M> Memory<'a, 'mir, 'tcx, M>
+where
+ M: Machine<'a, 'mir, 'tcx, PointerTag=()>,
+ M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<()>)>,
+{
/// mark an allocation as static and initialized, either mutable or not
pub fn intern_static(
&mut self,
let (kind, mut alloc) = self.alloc_map.remove(&alloc_id).unwrap();
match kind {
MemoryKind::Machine(_) => bug!("Static cannot refer to machine memory"),
- MemoryKind::Stack => {},
+ MemoryKind::Stack | MemoryKind::Vtable => {},
}
// ensure llvm knows not to put this into immutable memory
alloc.mutability = mutability;
let alloc = self.tcx.intern_const_alloc(alloc);
self.tcx.alloc_map.lock().set_id_memory(alloc_id, alloc);
// recurse into inner allocations
- for &alloc in alloc.relocations.values() {
+ for &(_, alloc) in alloc.relocations.values() {
// FIXME: Reusing the mutability here is likely incorrect. It is originally
// determined via `is_freeze`, and data is considered frozen if there is no
// `UnsafeCell` *immediately* in that data -- however, this search stops
}
Ok(())
}
+}
- /// The alloc_id must refer to a (mutable) static; a deep copy of that
- /// static is made into this memory.
- fn deep_copy_static(
- &mut self,
- id: AllocId,
- kind: MemoryKind<M::MemoryKinds>,
- ) -> EvalResult<'tcx> {
- let alloc = Self::get_static_alloc(self.tcx, id)?;
- if alloc.mutability == Mutability::Immutable {
- return err!(ModifiedConstantMemory);
- }
- let old = self.alloc_map.insert(id, (kind, alloc.clone()));
- assert!(old.is_none(), "deep_copy_static: must not overwrite existing memory");
- Ok(())
- }
-
+/// Reading and writing
+impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
pub fn copy(
&mut self,
- src: Scalar,
+ src: Scalar<M::PointerTag>,
src_align: Align,
- dest: Scalar,
+ dest: Scalar<M::PointerTag>,
dest_align: Align,
size: Size,
nonoverlapping: bool,
pub fn copy_repeatedly(
&mut self,
- src: Scalar,
+ src: Scalar<M::PointerTag>,
src_align: Align,
- dest: Scalar,
+ dest: Scalar<M::PointerTag>,
dest_align: Align,
size: Size,
length: u64,
new_relocations.extend(
relocations
.iter()
- .map(|&(offset, alloc_id)| {
+ .map(|&(offset, reloc)| {
(offset + dest.offset - src.offset + (i * size * relocations.len() as u64),
- alloc_id)
+ reloc)
})
);
}
// SAFE: The above indexing would have panicked if there weren't at least `size` bytes
// behind `src` and `dest`. Also, we use the overlapping-safe `ptr::copy` if `src` and
// `dest` could possibly overlap.
+ // The pointers above remain valid even if the `HashMap` table is moved around because they
+ // point into the `Vec` storing the bytes.
unsafe {
assert_eq!(size.bytes() as usize as u64, size.bytes());
if src.alloc_id == dest.alloc_id {
Ok(())
}
- pub fn read_c_str(&self, ptr: Pointer) -> EvalResult<'tcx, &[u8]> {
+ pub fn read_c_str(&self, ptr: Pointer<M::PointerTag>) -> EvalResult<'tcx, &[u8]> {
let alloc = self.get(ptr.alloc_id)?;
assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes());
let offset = ptr.offset.bytes() as usize;
self.check_defined(ptr, p1)?;
Ok(&alloc.bytes[offset..offset + size])
}
- None => err!(UnterminatedCString(ptr)),
+ None => err!(UnterminatedCString(ptr.erase_tag())),
}
}
- pub fn read_bytes(&self, ptr: Scalar, size: Size) -> EvalResult<'tcx, &[u8]> {
+ pub fn read_bytes(&self, ptr: Scalar<M::PointerTag>, size: Size) -> EvalResult<'tcx, &[u8]> {
// Empty accesses don't need to be valid pointers, but they should still be non-NULL
let align = Align::from_bytes(1, 1).unwrap();
if size.bytes() == 0 {
self.get_bytes(ptr.to_ptr()?, size, align)
}
- pub fn write_bytes(&mut self, ptr: Scalar, src: &[u8]) -> EvalResult<'tcx> {
+ pub fn write_bytes(&mut self, ptr: Scalar<M::PointerTag>, src: &[u8]) -> EvalResult<'tcx> {
// Empty accesses don't need to be valid pointers, but they should still be non-NULL
let align = Align::from_bytes(1, 1).unwrap();
if src.is_empty() {
Ok(())
}
- pub fn write_repeat(&mut self, ptr: Scalar, val: u8, count: Size) -> EvalResult<'tcx> {
+ pub fn write_repeat(
+ &mut self,
+ ptr: Scalar<M::PointerTag>,
+ val: u8,
+ count: Size
+ ) -> EvalResult<'tcx> {
// Empty accesses don't need to be valid pointers, but they should still be non-NULL
let align = Align::from_bytes(1, 1).unwrap();
if count.bytes() == 0 {
/// Read a *non-ZST* scalar
pub fn read_scalar(
&self,
- ptr: Pointer,
+ ptr: Pointer<M::PointerTag>,
ptr_align: Align,
size: Size
- ) -> EvalResult<'tcx, ScalarMaybeUndef> {
+ ) -> EvalResult<'tcx, ScalarMaybeUndef<M::PointerTag>> {
// get_bytes_unchecked tests alignment and relocation edges
let bytes = self.get_bytes_with_undef_and_ptr(
ptr, size, ptr_align.min(self.int_align(size))
} else {
let alloc = self.get(ptr.alloc_id)?;
match alloc.relocations.get(&ptr.offset) {
- Some(&alloc_id) => {
- let ptr = Pointer::new(alloc_id, Size::from_bytes(bits as u64));
+ Some(&(tag, alloc_id)) => {
+ let ptr = Pointer::new_with_tag(alloc_id, Size::from_bytes(bits as u64), tag);
return Ok(ScalarMaybeUndef::Scalar(ptr.into()))
}
None => {},
Ok(ScalarMaybeUndef::Scalar(Scalar::from_uint(bits, size)))
}
- pub fn read_ptr_sized(&self, ptr: Pointer, ptr_align: Align)
- -> EvalResult<'tcx, ScalarMaybeUndef> {
+ pub fn read_ptr_sized(
+ &self,
+ ptr: Pointer<M::PointerTag>,
+ ptr_align: Align
+ ) -> EvalResult<'tcx, ScalarMaybeUndef<M::PointerTag>> {
self.read_scalar(ptr, ptr_align, self.pointer_size())
}
/// Write a *non-ZST* scalar
pub fn write_scalar(
&mut self,
- ptr: Pointer,
+ ptr: Pointer<M::PointerTag>,
ptr_align: Align,
- val: ScalarMaybeUndef,
+ val: ScalarMaybeUndef<M::PointerTag>,
type_size: Size,
) -> EvalResult<'tcx> {
let val = match val {
Scalar::Ptr(val) => {
self.get_mut(ptr.alloc_id)?.relocations.insert(
ptr.offset,
- val.alloc_id,
+ (val.tag, val.alloc_id),
);
}
_ => {}
Ok(())
}
- pub fn write_ptr_sized(&mut self, ptr: Pointer, ptr_align: Align, val: ScalarMaybeUndef)
- -> EvalResult<'tcx> {
+ pub fn write_ptr_sized(
+ &mut self,
+ ptr: Pointer<M::PointerTag>,
+ ptr_align: Align,
+ val: ScalarMaybeUndef<M::PointerTag>
+ ) -> EvalResult<'tcx> {
let ptr_size = self.pointer_size();
self.write_scalar(ptr.into(), ptr_align, val, ptr_size)
}
/// Return all relocations overlapping with the given ptr-offset pair.
fn relocations(
&self,
- ptr: Pointer,
+ ptr: Pointer<M::PointerTag>,
size: Size,
- ) -> EvalResult<'tcx, &[(Size, AllocId)]> {
+ ) -> EvalResult<'tcx, &[(Size, (M::PointerTag, AllocId))]> {
// We have to go back `pointer_size - 1` bytes, as that one would still overlap with
// the beginning of this range.
let start = ptr.offset.bytes().saturating_sub(self.pointer_size().bytes() - 1);
/// Check that there ar eno relocations overlapping with the given range.
#[inline(always)]
- fn check_relocations(&self, ptr: Pointer, size: Size) -> EvalResult<'tcx> {
+ fn check_relocations(&self, ptr: Pointer<M::PointerTag>, size: Size) -> EvalResult<'tcx> {
if self.relocations(ptr, size)?.len() != 0 {
err!(ReadPointerAsBytes)
} else {
/// uninitialized. This is a somewhat odd "spooky action at a distance",
/// but it allows strictly more code to run than if we would just error
/// immediately in that case.
- fn clear_relocations(&mut self, ptr: Pointer, size: Size) -> EvalResult<'tcx> {
+ fn clear_relocations(&mut self, ptr: Pointer<M::PointerTag>, size: Size) -> EvalResult<'tcx> {
// Find the start and end of the given range and its outermost relocations.
let (first, last) = {
// Find all relocations overlapping the given range.
/// Error if there are relocations overlapping with the egdes of the
/// given memory range.
#[inline]
- fn check_relocation_edges(&self, ptr: Pointer, size: Size) -> EvalResult<'tcx> {
+ fn check_relocation_edges(&self, ptr: Pointer<M::PointerTag>, size: Size) -> EvalResult<'tcx> {
self.check_relocations(ptr, Size::ZERO)?;
self.check_relocations(ptr.offset(size, self)?, Size::ZERO)?;
Ok(())
// FIXME: Add a fast version for the common, nonoverlapping case
fn copy_undef_mask(
&mut self,
- src: Pointer,
- dest: Pointer,
+ src: Pointer<M::PointerTag>,
+ dest: Pointer<M::PointerTag>,
size: Size,
repeat: u64,
) -> EvalResult<'tcx> {
/// Checks that a range of bytes is defined. If not, returns the `ReadUndefBytes`
/// error which will report the first byte which is undefined.
#[inline]
- fn check_defined(&self, ptr: Pointer, size: Size) -> EvalResult<'tcx> {
+ fn check_defined(&self, ptr: Pointer<M::PointerTag>, size: Size) -> EvalResult<'tcx> {
let alloc = self.get(ptr.alloc_id)?;
alloc.undef_mask.is_range_defined(
ptr.offset,
pub fn mark_definedness(
&mut self,
- ptr: Pointer,
+ ptr: Pointer<M::PointerTag>,
size: Size,
new_state: bool,
) -> EvalResult<'tcx> {
pub use self::memory::{Memory, MemoryKind};
-pub use self::machine::Machine;
+pub use self::machine::{Machine, AllocMap};
pub use self::operand::{ScalarMaybeUndef, Value, ValTy, Operand, OpTy};
+
+pub use self::validity::RefTracking;
use super::{EvalContext, Machine, MemPlace, MPlaceTy, MemoryKind};
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
-pub enum ScalarMaybeUndef<Id=AllocId> {
- Scalar(Scalar<Id>),
+pub enum ScalarMaybeUndef<Tag=(), Id=AllocId> {
+ Scalar(Scalar<Tag, Id>),
Undef,
}
-impl From<Scalar> for ScalarMaybeUndef {
+impl<Tag> From<Scalar<Tag>> for ScalarMaybeUndef<Tag> {
#[inline(always)]
- fn from(s: Scalar) -> Self {
+ fn from(s: Scalar<Tag>) -> Self {
ScalarMaybeUndef::Scalar(s)
}
}
-impl<'tcx> ScalarMaybeUndef {
+impl<'tcx> ScalarMaybeUndef<()> {
#[inline]
- pub fn not_undef(self) -> EvalResult<'static, Scalar> {
+ pub fn with_default_tag<Tag>(self) -> ScalarMaybeUndef<Tag>
+ where Tag: Default
+ {
+ match self {
+ ScalarMaybeUndef::Scalar(s) => ScalarMaybeUndef::Scalar(s.with_default_tag()),
+ ScalarMaybeUndef::Undef => ScalarMaybeUndef::Undef,
+ }
+ }
+}
+
+impl<'tcx, Tag> ScalarMaybeUndef<Tag> {
+ #[inline]
+ pub fn erase_tag(self) -> ScalarMaybeUndef
+ {
+ match self {
+ ScalarMaybeUndef::Scalar(s) => ScalarMaybeUndef::Scalar(s.erase_tag()),
+ ScalarMaybeUndef::Undef => ScalarMaybeUndef::Undef,
+ }
+ }
+
+ #[inline]
+ pub fn not_undef(self) -> EvalResult<'static, Scalar<Tag>> {
match self {
ScalarMaybeUndef::Scalar(scalar) => Ok(scalar),
ScalarMaybeUndef::Undef => err!(ReadUndefBytes(Size::from_bytes(0))),
}
#[inline(always)]
- pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
+ pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
self.not_undef()?.to_ptr()
}
/// In particular, thanks to `ScalarPair`, arithmetic operations and casts can be entirely
/// defined on `Value`, and do not have to work with a `Place`.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub enum Value<Id=AllocId> {
- Scalar(ScalarMaybeUndef<Id>),
- ScalarPair(ScalarMaybeUndef<Id>, ScalarMaybeUndef<Id>),
+pub enum Value<Tag=(), Id=AllocId> {
+ Scalar(ScalarMaybeUndef<Tag, Id>),
+ ScalarPair(ScalarMaybeUndef<Tag, Id>, ScalarMaybeUndef<Tag, Id>),
}
-impl<'tcx> Value {
+impl Value {
+ #[inline]
+ pub fn with_default_tag<Tag>(self) -> Value<Tag>
+ where Tag: Default
+ {
+ match self {
+ Value::Scalar(x) => Value::Scalar(x.with_default_tag()),
+ Value::ScalarPair(x, y) =>
+ Value::ScalarPair(x.with_default_tag(), y.with_default_tag()),
+ }
+ }
+}
+
+impl<'tcx, Tag> Value<Tag> {
+ #[inline]
+ pub fn erase_tag(self) -> Value
+ {
+ match self {
+ Value::Scalar(x) => Value::Scalar(x.erase_tag()),
+ Value::ScalarPair(x, y) =>
+ Value::ScalarPair(x.erase_tag(), y.erase_tag()),
+ }
+ }
+
pub fn new_slice(
- val: Scalar,
+ val: Scalar<Tag>,
len: u64,
cx: impl HasDataLayout
) -> Self {
Value::ScalarPair(val.into(), Scalar::from_uint(len, cx.data_layout().pointer_size).into())
}
- pub fn new_dyn_trait(val: Scalar, vtable: Pointer) -> Self {
+ pub fn new_dyn_trait(val: Scalar<Tag>, vtable: Pointer<Tag>) -> Self {
Value::ScalarPair(val.into(), Scalar::Ptr(vtable).into())
}
#[inline]
- pub fn to_scalar_or_undef(self) -> ScalarMaybeUndef {
+ pub fn to_scalar_or_undef(self) -> ScalarMaybeUndef<Tag> {
match self {
Value::Scalar(val) => val,
Value::ScalarPair(..) => bug!("Got a fat pointer where a scalar was expected"),
}
#[inline]
- pub fn to_scalar(self) -> EvalResult<'tcx, Scalar> {
+ pub fn to_scalar(self) -> EvalResult<'tcx, Scalar<Tag>> {
self.to_scalar_or_undef().not_undef()
}
#[inline]
- pub fn to_scalar_pair(self) -> EvalResult<'tcx, (Scalar, Scalar)> {
+ pub fn to_scalar_pair(self) -> EvalResult<'tcx, (Scalar<Tag>, Scalar<Tag>)> {
match self {
Value::Scalar(..) => bug!("Got a thin pointer where a scalar pair was expected"),
Value::ScalarPair(a, b) => Ok((a.not_undef()?, b.not_undef()?))
/// Convert the value into a pointer (or a pointer-sized integer).
/// Throws away the second half of a ScalarPair!
#[inline]
- pub fn to_scalar_ptr(self) -> EvalResult<'tcx, Scalar> {
+ pub fn to_scalar_ptr(self) -> EvalResult<'tcx, Scalar<Tag>> {
match self {
Value::Scalar(ptr) |
Value::ScalarPair(ptr, _) => ptr.not_undef(),
// ScalarPair needs a type to interpret, so we often have a value and a type together
// as input for binary and cast operations.
#[derive(Copy, Clone, Debug)]
-pub struct ValTy<'tcx> {
- value: Value,
+pub struct ValTy<'tcx, Tag=()> {
+ value: Value<Tag>,
pub layout: TyLayout<'tcx>,
}
-impl<'tcx> ::std::ops::Deref for ValTy<'tcx> {
- type Target = Value;
+impl<'tcx, Tag> ::std::ops::Deref for ValTy<'tcx, Tag> {
+ type Target = Value<Tag>;
#[inline(always)]
- fn deref(&self) -> &Value {
+ fn deref(&self) -> &Value<Tag> {
&self.value
}
}
/// or still in memory. The latter is an optimization, to delay reading that chunk of
/// memory and to avoid having to store arbitrary-sized data here.
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub enum Operand<Id=AllocId> {
- Immediate(Value<Id>),
- Indirect(MemPlace<Id>),
+pub enum Operand<Tag=(), Id=AllocId> {
+ Immediate(Value<Tag, Id>),
+ Indirect(MemPlace<Tag, Id>),
}
impl Operand {
#[inline]
- pub fn to_mem_place(self) -> MemPlace {
+ pub fn with_default_tag<Tag>(self) -> Operand<Tag>
+ where Tag: Default
+ {
+ match self {
+ Operand::Immediate(x) => Operand::Immediate(x.with_default_tag()),
+ Operand::Indirect(x) => Operand::Indirect(x.with_default_tag()),
+ }
+ }
+}
+
+impl<Tag> Operand<Tag> {
+ #[inline]
+ pub fn erase_tag(self) -> Operand
+ {
+ match self {
+ Operand::Immediate(x) => Operand::Immediate(x.erase_tag()),
+ Operand::Indirect(x) => Operand::Indirect(x.erase_tag()),
+ }
+ }
+
+ #[inline]
+ pub fn to_mem_place(self) -> MemPlace<Tag>
+ where Tag: ::std::fmt::Debug
+ {
match self {
Operand::Indirect(mplace) => mplace,
_ => bug!("to_mem_place: expected Operand::Indirect, got {:?}", self),
}
#[inline]
- pub fn to_immediate(self) -> Value {
+ pub fn to_immediate(self) -> Value<Tag>
+ where Tag: ::std::fmt::Debug
+ {
match self {
Operand::Immediate(val) => val,
_ => bug!("to_immediate: expected Operand::Immediate, got {:?}", self),
}
#[derive(Copy, Clone, Debug)]
-pub struct OpTy<'tcx> {
- crate op: Operand, // ideally we'd make this private, but const_prop needs this
+pub struct OpTy<'tcx, Tag=()> {
+ crate op: Operand<Tag>, // ideally we'd make this private, but const_prop needs this
pub layout: TyLayout<'tcx>,
}
-impl<'tcx> ::std::ops::Deref for OpTy<'tcx> {
- type Target = Operand;
+impl<'tcx, Tag> ::std::ops::Deref for OpTy<'tcx, Tag> {
+ type Target = Operand<Tag>;
#[inline(always)]
- fn deref(&self) -> &Operand {
+ fn deref(&self) -> &Operand<Tag> {
&self.op
}
}
-impl<'tcx> From<MPlaceTy<'tcx>> for OpTy<'tcx> {
+impl<'tcx, Tag: Copy> From<MPlaceTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
#[inline(always)]
- fn from(mplace: MPlaceTy<'tcx>) -> Self {
+ fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
OpTy {
op: Operand::Indirect(*mplace),
layout: mplace.layout
}
}
-impl<'tcx> From<ValTy<'tcx>> for OpTy<'tcx> {
+impl<'tcx, Tag> From<ValTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
#[inline(always)]
- fn from(val: ValTy<'tcx>) -> Self {
+ fn from(val: ValTy<'tcx, Tag>) -> Self {
OpTy {
op: Operand::Immediate(val.value),
layout: val.layout
}
// Validation needs to hash OpTy, but we cannot hash Layout -- so we just hash the type
-impl<'tcx> Hash for OpTy<'tcx> {
+impl<'tcx, Tag> Hash for OpTy<'tcx, Tag>
+ where Tag: Hash
+{
fn hash<H: Hasher>(&self, state: &mut H) {
self.op.hash(state);
self.layout.ty.hash(state);
}
}
-impl<'tcx> PartialEq for OpTy<'tcx> {
+impl<'tcx, Tag> PartialEq for OpTy<'tcx, Tag>
+ where Tag: PartialEq
+{
fn eq(&self, other: &Self) -> bool {
self.op == other.op && self.layout.ty == other.layout.ty
}
}
-impl<'tcx> Eq for OpTy<'tcx> {}
+impl<'tcx, Tag> Eq for OpTy<'tcx, Tag>
+ where Tag: Eq
+{}
+
+impl<'tcx, Tag> OpTy<'tcx, Tag>
+{
+ #[inline]
+ pub fn erase_tag(self) -> OpTy<'tcx>
+ {
+ OpTy {
+ op: self.op.erase_tag(),
+ layout: self.layout,
+ }
+ }
+}
// Use the existing layout if given (but sanity check in debug mode),
// or compute the layout.
/// Return None if the layout does not permit loading this as a value.
pub(super) fn try_read_value_from_mplace(
&self,
- mplace: MPlaceTy<'tcx>,
- ) -> EvalResult<'tcx, Option<Value>> {
+ mplace: MPlaceTy<'tcx, M::PointerTag>,
+ ) -> EvalResult<'tcx, Option<Value<M::PointerTag>>> {
if mplace.layout.is_unsized() {
// Dont touch unsized
return Ok(None);
/// in a `Value`, not on which data is stored there currently.
pub(crate) fn try_read_value(
&self,
- src: OpTy<'tcx>,
- ) -> EvalResult<'tcx, Result<Value, MemPlace>> {
+ src: OpTy<'tcx, M::PointerTag>,
+ ) -> EvalResult<'tcx, Result<Value<M::PointerTag>, MemPlace<M::PointerTag>>> {
Ok(match src.try_as_mplace() {
Ok(mplace) => {
if let Some(val) = self.try_read_value_from_mplace(mplace)? {
/// Read a value from a place, asserting that that is possible with the given layout.
#[inline(always)]
- pub fn read_value(&self, op: OpTy<'tcx>) -> EvalResult<'tcx, ValTy<'tcx>> {
+ pub fn read_value(
+ &self,
+ op: OpTy<'tcx, M::PointerTag>
+ ) -> EvalResult<'tcx, ValTy<'tcx, M::PointerTag>> {
if let Ok(value) = self.try_read_value(op)? {
Ok(ValTy { value, layout: op.layout })
} else {
}
/// Read a scalar from a place
- pub fn read_scalar(&self, op: OpTy<'tcx>) -> EvalResult<'tcx, ScalarMaybeUndef> {
+ pub fn read_scalar(
+ &self,
+ op: OpTy<'tcx, M::PointerTag>
+ ) -> EvalResult<'tcx, ScalarMaybeUndef<M::PointerTag>> {
match *self.read_value(op)? {
Value::ScalarPair(..) => bug!("got ScalarPair for type: {:?}", op.layout.ty),
Value::Scalar(val) => Ok(val),
// Turn the MPlace into a string (must already be dereferenced!)
pub fn read_str(
&self,
- mplace: MPlaceTy<'tcx>,
+ mplace: MPlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx, &str> {
let len = mplace.len(self)?;
let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len as u64))?;
Ok(str)
}
- pub fn uninit_operand(&mut self, layout: TyLayout<'tcx>) -> EvalResult<'tcx, Operand> {
+ pub fn uninit_operand(
+ &mut self,
+ layout: TyLayout<'tcx>
+ ) -> EvalResult<'tcx, Operand<M::PointerTag>> {
// This decides which types we will use the Immediate optimization for, and hence should
// match what `try_read_value` and `eval_place_to_op` support.
if layout.is_zst() {
/// Projection functions
pub fn operand_field(
&self,
- op: OpTy<'tcx>,
+ op: OpTy<'tcx, M::PointerTag>,
field: u64,
- ) -> EvalResult<'tcx, OpTy<'tcx>> {
+ ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
let base = match op.try_as_mplace() {
Ok(mplace) => {
// The easy case
pub fn operand_downcast(
&self,
- op: OpTy<'tcx>,
+ op: OpTy<'tcx, M::PointerTag>,
variant: usize,
- ) -> EvalResult<'tcx, OpTy<'tcx>> {
+ ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
// Downcasts only change the layout
Ok(match op.try_as_mplace() {
Ok(mplace) => {
// will always be a MemPlace.
pub(super) fn deref_operand(
&self,
- src: OpTy<'tcx>,
- ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+ src: OpTy<'tcx, M::PointerTag>,
+ ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
let val = self.read_value(src)?;
trace!("deref to {} on {:?}", val.layout.ty, *val);
Ok(self.ref_to_mplace(val)?)
pub fn operand_projection(
&self,
- base: OpTy<'tcx>,
+ base: OpTy<'tcx, M::PointerTag>,
proj_elem: &mir::PlaceElem<'tcx>,
- ) -> EvalResult<'tcx, OpTy<'tcx>> {
+ ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
use rustc::mir::ProjectionElem::*;
Ok(match *proj_elem {
Field(field, _) => self.operand_field(base, field.index() as u64)?,
&self,
mir_place: &mir::Place<'tcx>,
layout: Option<TyLayout<'tcx>>,
- ) -> EvalResult<'tcx, OpTy<'tcx>> {
+ ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
use rustc::mir::Place::*;
let op = match *mir_place {
Local(mir::RETURN_PLACE) => return err!(ReadFromReturnPointer),
&self,
mir_op: &mir::Operand<'tcx>,
layout: Option<TyLayout<'tcx>>,
- ) -> EvalResult<'tcx, OpTy<'tcx>> {
+ ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
use rustc::mir::Operand::*;
let op = match *mir_op {
// FIXME: do some more logic on `move` to invalidate the old location
pub(super) fn eval_operands(
&self,
ops: &[mir::Operand<'tcx>],
- ) -> EvalResult<'tcx, Vec<OpTy<'tcx>>> {
+ ) -> EvalResult<'tcx, Vec<OpTy<'tcx, M::PointerTag>>> {
ops.into_iter()
.map(|op| self.eval_operand(op, None))
.collect()
pub(super) fn const_value_to_op(
&self,
val: ConstValue<'tcx>,
- ) -> EvalResult<'tcx, Operand> {
+ ) -> EvalResult<'tcx, Operand<M::PointerTag>> {
trace!("const_value_to_op: {:?}", val);
match val {
ConstValue::Unevaluated(def_id, substs) => {
ConstValue::ByRef(id, alloc, offset) => {
// We rely on mutability being set correctly in that allocation to prevent writes
// where none should happen -- and for `static mut`, we copy on demand anyway.
- Ok(Operand::Indirect(MemPlace::from_ptr(Pointer::new(id, offset), alloc.align)))
+ Ok(Operand::Indirect(
+ MemPlace::from_ptr(Pointer::new(id, offset), alloc.align)
+ ).with_default_tag())
},
ConstValue::ScalarPair(a, b) =>
- Ok(Operand::Immediate(Value::ScalarPair(a.into(), b.into()))),
+ Ok(Operand::Immediate(Value::ScalarPair(a.into(), b.into())).with_default_tag()),
ConstValue::Scalar(x) =>
- Ok(Operand::Immediate(Value::Scalar(x.into()))),
+ Ok(Operand::Immediate(Value::Scalar(x.into())).with_default_tag()),
}
}
pub fn const_to_op(
&self,
cnst: &ty::Const<'tcx>,
- ) -> EvalResult<'tcx, OpTy<'tcx>> {
+ ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
let op = self.const_value_to_op(cnst.val)?;
Ok(OpTy { op, layout: self.layout_of(cnst.ty)? })
}
- pub(super) fn global_to_op(&self, gid: GlobalId<'tcx>) -> EvalResult<'tcx, Operand> {
+ pub(super) fn global_to_op(
+ &self,
+ gid: GlobalId<'tcx>
+ ) -> EvalResult<'tcx, Operand<M::PointerTag>> {
let cv = self.const_eval(gid)?;
self.const_value_to_op(cv.val)
}
/// Read discriminant, return the runtime value as well as the variant index.
pub fn read_discriminant(
&self,
- rval: OpTy<'tcx>,
+ rval: OpTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx, (u128, usize)> {
trace!("read_discriminant_value {:#?}", rval.layout);
if rval.layout.abi.is_uninhabited() {
pub fn binop_with_overflow(
&mut self,
op: mir::BinOp,
- left: ValTy<'tcx>,
- right: ValTy<'tcx>,
- dest: PlaceTy<'tcx>,
+ left: ValTy<'tcx, M::PointerTag>,
+ right: ValTy<'tcx, M::PointerTag>,
+ dest: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
let (val, overflowed) = self.binary_op_val(op, left, right)?;
let val = Value::ScalarPair(val.into(), Scalar::from_bool(overflowed).into());
pub fn binop_ignore_overflow(
&mut self,
op: mir::BinOp,
- left: ValTy<'tcx>,
- right: ValTy<'tcx>,
- dest: PlaceTy<'tcx>,
+ left: ValTy<'tcx, M::PointerTag>,
+ right: ValTy<'tcx, M::PointerTag>,
+ dest: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
let (val, _overflowed) = self.binary_op_val(op, left, right)?;
self.write_scalar(val, dest)
bin_op: mir::BinOp,
l: char,
r: char,
- ) -> EvalResult<'tcx, (Scalar, bool)> {
+ ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
use rustc::mir::BinOp::*;
let res = match bin_op {
bin_op: mir::BinOp,
l: bool,
r: bool,
- ) -> EvalResult<'tcx, (Scalar, bool)> {
+ ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
use rustc::mir::BinOp::*;
let res = match bin_op {
// passing in raw bits
l: u128,
r: u128,
- ) -> EvalResult<'tcx, (Scalar, bool)> {
+ ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
use rustc::mir::BinOp::*;
macro_rules! float_math {
left_layout: TyLayout<'tcx>,
r: u128,
right_layout: TyLayout<'tcx>,
- ) -> EvalResult<'tcx, (Scalar, bool)> {
+ ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
use rustc::mir::BinOp::*;
// Shift ops can have an RHS with a different numeric type.
pub fn binary_op_val(
&self,
bin_op: mir::BinOp,
- left: ValTy<'tcx>,
- right: ValTy<'tcx>,
- ) -> EvalResult<'tcx, (Scalar, bool)> {
+ left: ValTy<'tcx, M::PointerTag>,
+ right: ValTy<'tcx, M::PointerTag>,
+ ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
self.binary_op(
bin_op,
left.to_scalar()?, left.layout,
pub fn binary_op(
&self,
bin_op: mir::BinOp,
- left: Scalar,
+ left: Scalar<M::PointerTag>,
left_layout: TyLayout<'tcx>,
- right: Scalar,
+ right: Scalar<M::PointerTag>,
right_layout: TyLayout<'tcx>,
- ) -> EvalResult<'tcx, (Scalar, bool)> {
+ ) -> EvalResult<'tcx, (Scalar<M::PointerTag>, bool)> {
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
bin_op, left, left_layout.ty, right, right_layout.ty);
pub fn unary_op(
&self,
un_op: mir::UnOp,
- val: Scalar,
+ val: Scalar<M::PointerTag>,
layout: TyLayout<'tcx>,
- ) -> EvalResult<'tcx, Scalar> {
+ ) -> EvalResult<'tcx, Scalar<M::PointerTag>> {
use rustc::mir::UnOp::*;
use rustc_apfloat::ieee::{Single, Double};
use rustc_apfloat::Float;
//! All high-level functions to write to memory work on places as destinations.
use std::convert::TryFrom;
+use std::hash::Hash;
use rustc::mir;
use rustc::ty::{self, Ty};
use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout};
use rustc::mir::interpret::{
- GlobalId, AllocId, Scalar, EvalResult, Pointer, PointerArithmetic
+ GlobalId, AllocId, Allocation, Scalar, EvalResult, Pointer, PointerArithmetic
+};
+use super::{
+ EvalContext, Machine, AllocMap,
+ Value, ValTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind
};
-use super::{EvalContext, Machine, Value, ValTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind};
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub struct MemPlace<Id=AllocId> {
+pub struct MemPlace<Tag=(), Id=AllocId> {
/// A place may have an integral pointer for ZSTs, and since it might
/// be turned back into a reference before ever being dereferenced.
/// However, it may never be undef.
- pub ptr: Scalar<Id>,
+ pub ptr: Scalar<Tag, Id>,
pub align: Align,
/// Metadata for unsized places. Interpretation is up to the type.
/// Must not be present for sized types, but can be missing for unsized types
/// (e.g. `extern type`).
- pub extra: Option<Scalar<Id>>,
+ pub meta: Option<Scalar<Tag, Id>>,
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub enum Place<Id=AllocId> {
+pub enum Place<Tag=(), Id=AllocId> {
/// A place referring to a value allocated in the `Memory` system.
- Ptr(MemPlace<Id>),
+ Ptr(MemPlace<Tag, Id>),
/// To support alloc-free locals, we are able to write directly to a local.
/// (Without that optimization, we'd just always be a `MemPlace`.)
}
#[derive(Copy, Clone, Debug)]
-pub struct PlaceTy<'tcx> {
- place: Place,
+pub struct PlaceTy<'tcx, Tag=()> {
+ place: Place<Tag>,
pub layout: TyLayout<'tcx>,
}
-impl<'tcx> ::std::ops::Deref for PlaceTy<'tcx> {
- type Target = Place;
+impl<'tcx, Tag> ::std::ops::Deref for PlaceTy<'tcx, Tag> {
+ type Target = Place<Tag>;
#[inline(always)]
- fn deref(&self) -> &Place {
+ fn deref(&self) -> &Place<Tag> {
&self.place
}
}
/// A MemPlace with its layout. Constructing it is only possible in this module.
#[derive(Copy, Clone, Debug)]
-pub struct MPlaceTy<'tcx> {
- mplace: MemPlace,
+pub struct MPlaceTy<'tcx, Tag=()> {
+ mplace: MemPlace<Tag>,
pub layout: TyLayout<'tcx>,
}
-impl<'tcx> ::std::ops::Deref for MPlaceTy<'tcx> {
- type Target = MemPlace;
+impl<'tcx, Tag> ::std::ops::Deref for MPlaceTy<'tcx, Tag> {
+ type Target = MemPlace<Tag>;
#[inline(always)]
- fn deref(&self) -> &MemPlace {
+ fn deref(&self) -> &MemPlace<Tag> {
&self.mplace
}
}
-impl<'tcx> From<MPlaceTy<'tcx>> for PlaceTy<'tcx> {
+impl<'tcx, Tag> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
#[inline(always)]
- fn from(mplace: MPlaceTy<'tcx>) -> Self {
+ fn from(mplace: MPlaceTy<'tcx, Tag>) -> Self {
PlaceTy {
place: Place::Ptr(mplace.mplace),
layout: mplace.layout
}
impl MemPlace {
+ #[inline]
+ pub fn with_default_tag<Tag>(self) -> MemPlace<Tag>
+ where Tag: Default
+ {
+ MemPlace {
+ ptr: self.ptr.with_default_tag(),
+ align: self.align,
+ meta: self.meta.map(Scalar::with_default_tag),
+ }
+ }
+}
+
+impl<Tag> MemPlace<Tag> {
+ #[inline]
+ pub fn erase_tag(self) -> MemPlace
+ {
+ MemPlace {
+ ptr: self.ptr.erase_tag(),
+ align: self.align,
+ meta: self.meta.map(Scalar::erase_tag),
+ }
+ }
+
#[inline(always)]
- pub fn from_scalar_ptr(ptr: Scalar, align: Align) -> Self {
+ pub fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
MemPlace {
ptr,
align,
- extra: None,
+ meta: None,
}
}
#[inline(always)]
- pub fn from_ptr(ptr: Pointer, align: Align) -> Self {
+ pub fn from_ptr(ptr: Pointer<Tag>, align: Align) -> Self {
Self::from_scalar_ptr(ptr.into(), align)
}
#[inline(always)]
- pub fn to_scalar_ptr_align(self) -> (Scalar, Align) {
- assert_eq!(self.extra, None);
+ pub fn to_scalar_ptr_align(self) -> (Scalar<Tag>, Align) {
+ assert!(self.meta.is_none());
(self.ptr, self.align)
}
- /// Extract the ptr part of the mplace
+ /// metact the ptr part of the mplace
#[inline(always)]
- pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
+ pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
// At this point, we forget about the alignment information --
// the place has been turned into a reference, and no matter where it came from,
// it now must be aligned.
/// Turn a mplace into a (thin or fat) pointer, as a reference, pointing to the same space.
/// This is the inverse of `ref_to_mplace`.
- pub fn to_ref(self) -> Value {
+ pub fn to_ref(self) -> Value<Tag> {
// We ignore the alignment of the place here -- special handling for packed structs ends
// at the `&` operator.
- match self.extra {
+ match self.meta {
None => Value::Scalar(self.ptr.into()),
- Some(extra) => Value::ScalarPair(self.ptr.into(), extra.into()),
+ Some(meta) => Value::ScalarPair(self.ptr.into(), meta.into()),
}
}
}
-impl<'tcx> MPlaceTy<'tcx> {
+impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
+ /// Produces a MemPlace that works for ZST but nothing else
#[inline]
- fn from_aligned_ptr(ptr: Pointer, layout: TyLayout<'tcx>) -> Self {
+ pub fn dangling(layout: TyLayout<'tcx>, cx: impl HasDataLayout) -> Self {
+ MPlaceTy {
+ mplace: MemPlace::from_scalar_ptr(
+ Scalar::from_uint(layout.align.abi(), cx.pointer_size()),
+ layout.align
+ ),
+ layout
+ }
+ }
+
+ #[inline]
+ fn from_aligned_ptr(ptr: Pointer<Tag>, layout: TyLayout<'tcx>) -> Self {
MPlaceTy { mplace: MemPlace::from_ptr(ptr, layout.align), layout }
}
#[inline]
pub(super) fn len(self, cx: impl HasDataLayout) -> EvalResult<'tcx, u64> {
if self.layout.is_unsized() {
- // We need to consult `extra` metadata
+ // We need to consult `meta` metadata
match self.layout.ty.sty {
ty::Slice(..) | ty::Str =>
- return self.extra.unwrap().to_usize(cx),
+ return self.mplace.meta.unwrap().to_usize(cx),
_ => bug!("len not supported on unsized type {:?}", self.layout.ty),
}
} else {
}
#[inline]
- pub(super) fn vtable(self) -> EvalResult<'tcx, Pointer> {
+ pub(super) fn vtable(self) -> EvalResult<'tcx, Pointer<Tag>> {
match self.layout.ty.sty {
- ty::Dynamic(..) => self.extra.unwrap().to_ptr(),
+ ty::Dynamic(..) => self.mplace.meta.unwrap().to_ptr(),
_ => bug!("vtable not supported on type {:?}", self.layout.ty),
}
}
}
-impl<'tcx> OpTy<'tcx> {
+impl<'tcx, Tag: ::std::fmt::Debug> OpTy<'tcx, Tag> {
#[inline(always)]
- pub fn try_as_mplace(self) -> Result<MPlaceTy<'tcx>, Value> {
- match *self {
+ pub fn try_as_mplace(self) -> Result<MPlaceTy<'tcx, Tag>, Value<Tag>> {
+ match self.op {
Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }),
Operand::Immediate(value) => Err(value),
}
}
#[inline(always)]
- pub fn to_mem_place(self) -> MPlaceTy<'tcx> {
+ pub fn to_mem_place(self) -> MPlaceTy<'tcx, Tag> {
self.try_as_mplace().unwrap()
}
}
-impl<'tcx> Place {
+impl<'tcx, Tag: ::std::fmt::Debug> Place<Tag> {
/// Produces a Place that will error if attempted to be read from or written to
#[inline]
pub fn null(cx: impl HasDataLayout) -> Self {
}
#[inline]
- pub fn from_scalar_ptr(ptr: Scalar, align: Align) -> Self {
+ pub fn from_scalar_ptr(ptr: Scalar<Tag>, align: Align) -> Self {
Place::Ptr(MemPlace::from_scalar_ptr(ptr, align))
}
#[inline]
- pub fn from_ptr(ptr: Pointer, align: Align) -> Self {
+ pub fn from_ptr(ptr: Pointer<Tag>, align: Align) -> Self {
Place::Ptr(MemPlace::from_ptr(ptr, align))
}
#[inline]
- pub fn to_mem_place(self) -> MemPlace {
+ pub fn to_mem_place(self) -> MemPlace<Tag> {
match self {
Place::Ptr(mplace) => mplace,
_ => bug!("to_mem_place: expected Place::Ptr, got {:?}", self),
}
#[inline]
- pub fn to_scalar_ptr_align(self) -> (Scalar, Align) {
+ pub fn to_scalar_ptr_align(self) -> (Scalar<Tag>, Align) {
self.to_mem_place().to_scalar_ptr_align()
}
#[inline]
- pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
+ pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
self.to_mem_place().to_ptr()
}
}
-impl<'tcx> PlaceTy<'tcx> {
+impl<'tcx, Tag: ::std::fmt::Debug> PlaceTy<'tcx, Tag> {
/// Produces a Place that will error if attempted to be read from or written to
#[inline]
pub fn null(cx: impl HasDataLayout, layout: TyLayout<'tcx>) -> Self {
}
#[inline]
- pub fn to_mem_place(self) -> MPlaceTy<'tcx> {
+ pub fn to_mem_place(self) -> MPlaceTy<'tcx, Tag> {
MPlaceTy { mplace: self.place.to_mem_place(), layout: self.layout }
}
}
-impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
+// separating the pointer tag for `impl Trait`, see https://github.com/rust-lang/rust/issues/54385
+impl<'a, 'mir, 'tcx, Tag, M> EvalContext<'a, 'mir, 'tcx, M>
+where
+ Tag: ::std::fmt::Debug+Default+Copy+Eq+Hash+'static,
+ M: Machine<'a, 'mir, 'tcx, PointerTag=Tag>,
+ M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<Tag>)>,
+{
/// Take a value, which represents a (thin or fat) reference, and make it a place.
/// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref`.
pub fn ref_to_mplace(
- &self, val: ValTy<'tcx>
- ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+ &self, val: ValTy<'tcx, M::PointerTag>
+ ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
let pointee_type = val.layout.ty.builtin_deref(true).unwrap().ty;
let layout = self.layout_of(pointee_type)?;
let align = layout.align;
let mplace = match *val {
Value::Scalar(ptr) =>
- MemPlace { ptr: ptr.not_undef()?, align, extra: None },
- Value::ScalarPair(ptr, extra) =>
- MemPlace { ptr: ptr.not_undef()?, align, extra: Some(extra.not_undef()?) },
+ MemPlace { ptr: ptr.not_undef()?, align, meta: None },
+ Value::ScalarPair(ptr, meta) =>
+ MemPlace { ptr: ptr.not_undef()?, align, meta: Some(meta.not_undef()?) },
};
Ok(MPlaceTy { mplace, layout })
}
#[inline(always)]
pub fn mplace_field(
&self,
- base: MPlaceTy<'tcx>,
+ base: MPlaceTy<'tcx, M::PointerTag>,
field: u64,
- ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+ ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
// Not using the layout method because we want to compute on u64
let offset = match base.layout.fields {
layout::FieldPlacement::Arbitrary { ref offsets, .. } =>
let field_layout = base.layout.field(self, usize::try_from(field).unwrap_or(0))?;
// Offset may need adjustment for unsized fields
- let (extra, offset) = if field_layout.is_unsized() {
+ let (meta, offset) = if field_layout.is_unsized() {
// re-use parent metadata to determine dynamic field layout
- let (_, align) = self.size_and_align_of(base.extra, field_layout)?;
- (base.extra, offset.abi_align(align))
+ let (_, align) = self.size_and_align_of(base.meta, field_layout)?;
+ (base.meta, offset.abi_align(align))
} else {
- // base.extra could be present; we might be accessing a sized field of an unsized
+ // base.meta could be present; we might be accessing a sized field of an unsized
// struct.
(None, offset)
};
// codegen -- mostly to see if we can get away with that
.restrict_for_offset(offset); // must be last thing that happens
- Ok(MPlaceTy { mplace: MemPlace { ptr, align, extra }, layout: field_layout })
+ Ok(MPlaceTy { mplace: MemPlace { ptr, align, meta }, layout: field_layout })
}
// Iterates over all fields of an array. Much more efficient than doing the
// same by repeatedly calling `mplace_array`.
pub fn mplace_array_fields(
&self,
- base: MPlaceTy<'tcx>,
- ) -> EvalResult<'tcx, impl Iterator<Item=EvalResult<'tcx, MPlaceTy<'tcx>>> + 'a> {
+ base: MPlaceTy<'tcx, Tag>,
+ ) ->
+ EvalResult<'tcx, impl Iterator<Item=EvalResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'a>
+ {
let len = base.len(self)?; // also asserts that we have a type where this makes sense
let stride = match base.layout.fields {
layout::FieldPlacement::Array { stride, .. } => stride,
Ok((0..len).map(move |i| {
let ptr = base.ptr.ptr_offset(i * stride, dl)?;
Ok(MPlaceTy {
- mplace: MemPlace { ptr, align: base.align, extra: None },
+ mplace: MemPlace { ptr, align: base.align, meta: None },
layout
})
}))
pub fn mplace_subslice(
&self,
- base: MPlaceTy<'tcx>,
+ base: MPlaceTy<'tcx, M::PointerTag>,
from: u64,
to: u64,
- ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+ ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
let len = base.len(self)?; // also asserts that we have a type where this makes sense
assert!(from <= len - to);
};
let ptr = base.ptr.ptr_offset(from_offset, self)?;
- // Compute extra and new layout
+ // Compute meta and new layout
let inner_len = len - to - from;
- let (extra, ty) = match base.layout.ty.sty {
+ let (meta, ty) = match base.layout.ty.sty {
// It is not nice to match on the type, but that seems to be the only way to
// implement this.
ty::Array(inner, _) =>
let layout = self.layout_of(ty)?;
Ok(MPlaceTy {
- mplace: MemPlace { ptr, align: base.align, extra },
+ mplace: MemPlace { ptr, align: base.align, meta },
layout
})
}
pub fn mplace_downcast(
&self,
- base: MPlaceTy<'tcx>,
+ base: MPlaceTy<'tcx, M::PointerTag>,
variant: usize,
- ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+ ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
// Downcasts only change the layout
- assert_eq!(base.extra, None);
+ assert!(base.meta.is_none());
Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base })
}
/// Project into an mplace
pub fn mplace_projection(
&self,
- base: MPlaceTy<'tcx>,
+ base: MPlaceTy<'tcx, M::PointerTag>,
proj_elem: &mir::PlaceElem<'tcx>,
- ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+ ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
use rustc::mir::ProjectionElem::*;
Ok(match *proj_elem {
Field(field, _) => self.mplace_field(base, field.index() as u64)?,
/// Just a convenience function, but used quite a bit.
pub fn place_field(
&mut self,
- base: PlaceTy<'tcx>,
+ base: PlaceTy<'tcx, M::PointerTag>,
field: u64,
- ) -> EvalResult<'tcx, PlaceTy<'tcx>> {
+ ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
// FIXME: We could try to be smarter and avoid allocation for fields that span the
// entire place.
let mplace = self.force_allocation(base)?;
pub fn place_downcast(
&mut self,
- base: PlaceTy<'tcx>,
+ base: PlaceTy<'tcx, M::PointerTag>,
variant: usize,
- ) -> EvalResult<'tcx, PlaceTy<'tcx>> {
+ ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
// Downcast just changes the layout
Ok(match base.place {
Place::Ptr(mplace) =>
/// Project into a place
pub fn place_projection(
&mut self,
- base: PlaceTy<'tcx>,
+ base: PlaceTy<'tcx, M::PointerTag>,
proj_elem: &mir::ProjectionElem<'tcx, mir::Local, Ty<'tcx>>,
- ) -> EvalResult<'tcx, PlaceTy<'tcx>> {
+ ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
use rustc::mir::ProjectionElem::*;
Ok(match *proj_elem {
Field(field, _) => self.place_field(base, field.index() as u64)?,
pub(super) fn eval_place_to_mplace(
&self,
mir_place: &mir::Place<'tcx>
- ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+ ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
use rustc::mir::Place::*;
Ok(match *mir_place {
Promoted(ref promoted) => {
// and miri: They use the same query to eventually obtain a `ty::Const`
// and use that for further computation.
let alloc = self.tcx.alloc_map.lock().intern_static(cid.instance.def_id());
- MPlaceTy::from_aligned_ptr(alloc.into(), layout)
+ MPlaceTy::from_aligned_ptr(Pointer::from(alloc).with_default_tag(), layout)
}
_ => bug!("eval_place_to_mplace called on {:?}", mir_place),
/// Compute a place. You should only use this if you intend to write into this
/// place; for reading, a more efficient alternative is `eval_place_for_read`.
- pub fn eval_place(&mut self, mir_place: &mir::Place<'tcx>) -> EvalResult<'tcx, PlaceTy<'tcx>> {
+ pub fn eval_place(
+ &mut self,
+ mir_place: &mir::Place<'tcx>
+ ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
use rustc::mir::Place::*;
let place = match *mir_place {
Local(mir::RETURN_PLACE) => PlaceTy {
/// Write a scalar to a place
pub fn write_scalar(
&mut self,
- val: impl Into<ScalarMaybeUndef>,
- dest: PlaceTy<'tcx>,
+ val: impl Into<ScalarMaybeUndef<M::PointerTag>>,
+ dest: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
self.write_value(Value::Scalar(val.into()), dest)
}
/// Write a value to a place
pub fn write_value(
&mut self,
- src_val: Value,
- dest: PlaceTy<'tcx>,
+ src_val: Value<M::PointerTag>,
+ dest: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
trace!("write_value: {:?} <- {:?}", *dest, src_val);
+ // Check that the value actually is okay for that type
+ if M::ENFORCE_VALIDITY {
+ // Something changed somewhere, better make sure it matches the type!
+ let op = OpTy { op: Operand::Immediate(src_val), layout: dest.layout };
+ self.validate_operand(op, &mut vec![], None, /*const_mode*/false)?;
+ }
+
// See if we can avoid an allocation. This is the counterpart to `try_read_value`,
// but not factored as a separate function.
let mplace = match dest.place {
self.write_value_to_mplace(src_val, dest)
}
- /// Write a value to memory
+ /// Write a value to memory. This does NOT do validation, so you better had already
+ /// done that before calling this!
fn write_value_to_mplace(
&mut self,
- value: Value,
- dest: MPlaceTy<'tcx>,
+ value: Value<M::PointerTag>,
+ dest: MPlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
let (ptr, ptr_align) = dest.to_scalar_ptr_align();
// Note that it is really important that the type here is the right one, and matches the
/// Copy the data from an operand to a place
pub fn copy_op(
&mut self,
- src: OpTy<'tcx>,
- dest: PlaceTy<'tcx>,
+ src: OpTy<'tcx, M::PointerTag>,
+ dest: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
assert!(!src.layout.is_unsized() && !dest.layout.is_unsized(),
"Cannot copy unsized data");
};
// Slow path, this does not fit into an immediate. Just memcpy.
trace!("copy_op: {:?} <- {:?}", *dest, *src);
- let (dest_ptr, dest_align) = self.force_allocation(dest)?.to_scalar_ptr_align();
+ let dest = self.force_allocation(dest)?;
+ let (dest_ptr, dest_align) = dest.to_scalar_ptr_align();
self.memory.copy(
src_ptr, src_align,
dest_ptr, dest_align,
src.layout.size, false
- )
+ )?;
+ if M::ENFORCE_VALIDITY {
+ // Something changed somewhere, better make sure it matches the type!
+ self.validate_operand(dest.into(), &mut vec![], None, /*const_mode*/false)?;
+ }
+ Ok(())
}
/// Make sure that a place is in memory, and return where it is.
/// This is essentially `force_to_memplace`.
pub fn force_allocation(
&mut self,
- place: PlaceTy<'tcx>,
- ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+ place: PlaceTy<'tcx, M::PointerTag>,
+ ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
let mplace = match place.place {
Place::Local { frame, local } => {
match *self.stack[frame].locals[local].access()? {
// that has different alignment than the outer field.
let local_layout = self.layout_of_local(frame, local)?;
let ptr = self.allocate(local_layout, MemoryKind::Stack)?;
+ // We don't have to validate as we can assume the local
+ // was already valid for its type.
self.write_value_to_mplace(value, ptr)?;
let mplace = ptr.mplace;
// Update the local
&mut self,
layout: TyLayout<'tcx>,
kind: MemoryKind<M::MemoryKinds>,
- ) -> EvalResult<'tcx, MPlaceTy<'tcx>> {
+ ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
assert!(!layout.is_unsized(), "cannot alloc memory for unsized type");
let ptr = self.memory.allocate(layout.size, layout.align, kind)?;
Ok(MPlaceTy::from_aligned_ptr(ptr, layout))
pub fn write_discriminant_index(
&mut self,
variant_index: usize,
- dest: PlaceTy<'tcx>,
+ dest: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
match dest.layout.variants {
layout::Variants::Single { index } => {
/// Every place can be read from, so we can turm them into an operand
#[inline(always)]
- pub fn place_to_op(&self, place: PlaceTy<'tcx>) -> EvalResult<'tcx, OpTy<'tcx>> {
+ pub fn place_to_op(
+ &self,
+ place: PlaceTy<'tcx, M::PointerTag>
+ ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
let op = match place.place {
Place::Ptr(mplace) => {
Operand::Indirect(mplace)
/// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.
/// Also return some more information so drop doesn't have to run the same code twice.
- pub(super) fn unpack_dyn_trait(&self, mplace: MPlaceTy<'tcx>)
- -> EvalResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx>)> {
+ pub(super) fn unpack_dyn_trait(&self, mplace: MPlaceTy<'tcx, M::PointerTag>)
+ -> EvalResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::PointerTag>)> {
let vtable = mplace.vtable()?; // also sanity checks the type
let (instance, ty) = self.read_drop_type_from_vtable(vtable)?;
let layout = self.layout_of(ty)?;
}
let mplace = MPlaceTy {
- mplace: MemPlace { extra: None, ..*mplace },
+ mplace: MemPlace { meta: None, ..*mplace },
layout
};
Ok((instance, mplace))
($field:ident, $ctx:expr, $delegate:expr) => ($delegate);
}
+// This assumes the type has two type parameters, first for the tag (set to `()`),
+// then for the id
macro_rules! impl_snapshot_for {
// FIXME(mark-i-m): Some of these should be `?` rather than `*`.
(enum $enum_name:ident {
impl<'a, Ctx> self::Snapshot<'a, Ctx> for $enum_name
where Ctx: self::SnapshotContext<'a>,
{
- type Item = $enum_name<AllocIdSnapshot<'a>>;
+ type Item = $enum_name<(), AllocIdSnapshot<'a>>;
#[inline]
fn snapshot(&self, __ctx: &'a Ctx) -> Self::Item {
impl<'a, Ctx> self::Snapshot<'a, Ctx> for $struct_name
where Ctx: self::SnapshotContext<'a>,
{
- type Item = $struct_name<AllocIdSnapshot<'a>>;
+ type Item = $struct_name<(), AllocIdSnapshot<'a>>;
#[inline]
fn snapshot(&self, __ctx: &'a Ctx) -> Self::Item {
impl_snapshot_for!(struct Pointer {
alloc_id,
offset -> *offset, // just copy offset verbatim
+ tag -> *tag, // just copy tag
});
impl<'a, Ctx> Snapshot<'a, Ctx> for Scalar
where Ctx: SnapshotContext<'a>,
{
- type Item = Scalar<AllocIdSnapshot<'a>>;
+ type Item = Scalar<(), AllocIdSnapshot<'a>>;
fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
match self {
impl_stable_hash_for!(struct ::interpret::MemPlace {
ptr,
align,
- extra,
+ meta,
});
impl_snapshot_for!(struct MemPlace {
ptr,
- extra,
+ meta,
align -> *align, // just copy alignment verbatim
});
impl<'a, Ctx> Snapshot<'a, Ctx> for Place
where Ctx: SnapshotContext<'a>,
{
- type Item = Place<AllocIdSnapshot<'a>>;
+ type Item = Place<(), AllocIdSnapshot<'a>>;
fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
match self {
impl<'a, Ctx> Snapshot<'a, Ctx> for Relocations
where Ctx: SnapshotContext<'a>,
{
- type Item = Relocations<AllocIdSnapshot<'a>>;
+ type Item = Relocations<(), AllocIdSnapshot<'a>>;
fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
Relocations::from_presorted(self.iter()
- .map(|(size, id)| (*size, id.snapshot(ctx)))
+ .map(|(size, ((), id))| (*size, ((), id.snapshot(ctx))))
.collect())
}
}
#[derive(Eq, PartialEq)]
struct AllocationSnapshot<'a> {
bytes: &'a [u8],
- relocations: Relocations<AllocIdSnapshot<'a>>,
+ relocations: Relocations<(), AllocIdSnapshot<'a>>,
undef_mask: &'a UndefMask,
align: &'a Align,
mutability: &'a Mutability,
instance: &'a ty::Instance<'tcx>,
span: &'a Span,
return_to_block: &'a StackPopCleanup,
- return_place: Place<AllocIdSnapshot<'a>>,
- locals: IndexVec<mir::Local, LocalValue<AllocIdSnapshot<'a>>>,
+ return_place: Place<(), AllocIdSnapshot<'a>>,
+ locals: IndexVec<mir::Local, LocalValue<(), AllocIdSnapshot<'a>>>,
block: &'a mir::BasicBlock,
stmt: usize,
}
fn pass_argument(
&mut self,
skip_zst: bool,
- caller_arg: &mut impl Iterator<Item=OpTy<'tcx>>,
- callee_arg: PlaceTy<'tcx>,
+ caller_arg: &mut impl Iterator<Item=OpTy<'tcx, M::PointerTag>>,
+ callee_arg: PlaceTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx> {
if skip_zst && callee_arg.layout.is_zst() {
// Nothing to do.
instance: ty::Instance<'tcx>,
span: Span,
caller_abi: Abi,
- args: &[OpTy<'tcx>],
- dest: Option<PlaceTy<'tcx>>,
+ args: &[OpTy<'tcx, M::PointerTag>],
+ dest: Option<PlaceTy<'tcx, M::PointerTag>>,
ret: Option<mir::BasicBlock>,
) -> EvalResult<'tcx> {
trace!("eval_fn_call: {:#?}", instance);
let return_place = match dest {
Some(place) => *place,
- None => Place::null(&self),
+ None => Place::null(&self), // any access will error. good!
};
self.push_stack_frame(
instance,
// last incoming argument. These two iterators do not have the same type,
// so to keep the code paths uniform we accept an allocation
// (for RustCall ABI only).
- let caller_args : Cow<[OpTy<'tcx>]> =
+ let caller_args : Cow<[OpTy<'tcx, M::PointerTag>]> =
if caller_abi == Abi::RustCall && !args.is_empty() {
// Untuple
let (&untuple_arg, args) = args.split_last().unwrap();
.chain((0..untuple_arg.layout.fields.count()).into_iter()
.map(|i| self.operand_field(untuple_arg, i as u64))
)
- .collect::<EvalResult<Vec<OpTy<'tcx>>>>()?)
+ .collect::<EvalResult<Vec<OpTy<'tcx, M::PointerTag>>>>()?)
} else {
// Plain arg passing
Cow::from(args)
trace!("Caller has too many args over");
return err!(FunctionArgCountMismatch);
}
+ // Don't forget to check the return type!
+ if let Some(caller_ret) = dest {
+ let callee_ret = self.eval_place(&mir::Place::Local(mir::RETURN_PLACE))?;
+ if !Self::check_argument_compat(caller_ret.layout, callee_ret.layout) {
+ return err!(FunctionRetMismatch(
+ caller_ret.layout.ty, callee_ret.layout.ty
+ ));
+ }
+ } else {
+ // FIXME: The caller thinks this function cannot return. How do
+ // we verify that the callee agrees?
+ // On the plus side, the the callee ever writes to its return place,
+ // that will be detected as UB (because we set that to NULL above).
+ }
Ok(())
})();
match res {
fn drop_in_place(
&mut self,
- place: PlaceTy<'tcx>,
+ place: PlaceTy<'tcx, M::PointerTag>,
instance: ty::Instance<'tcx>,
span: Span,
target: mir::BasicBlock,
use rustc::ty::layout::{Size, Align, LayoutOf};
use rustc::mir::interpret::{Scalar, Pointer, EvalResult, PointerArithmetic};
-use syntax::ast::Mutability;
-
use super::{EvalContext, Machine, MemoryKind};
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
&mut self,
ty: Ty<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
- ) -> EvalResult<'tcx, Pointer> {
+ ) -> EvalResult<'tcx, Pointer<M::PointerTag>> {
debug!("get_vtable(trait_ref={:?})", trait_ref);
+ // FIXME: Cache this!
+
let layout = self.layout_of(trait_ref.self_ty())?;
assert!(!layout.is_unsized(), "can't create a vtable for an unsized type");
let size = layout.size.bytes();
let vtable = self.memory.allocate(
ptr_size * (3 + methods.len() as u64),
ptr_align,
- MemoryKind::Stack,
+ MemoryKind::Vtable,
)?;
let drop = ::monomorphize::resolve_drop_in_place(*self.tcx, ty);
}
}
- self.memory.intern_static(
- vtable.alloc_id,
- Mutability::Immutable,
- )?;
+ self.memory.mark_immutable(vtable.alloc_id)?;
Ok(vtable)
}
/// Return the drop fn instance as well as the actual dynamic type
pub fn read_drop_type_from_vtable(
&self,
- vtable: Pointer,
+ vtable: Pointer<M::PointerTag>,
) -> EvalResult<'tcx, (ty::Instance<'tcx>, ty::Ty<'tcx>)> {
// we don't care about the pointee type, we just want a pointer
let pointer_align = self.tcx.data_layout.pointer_align;
pub fn read_size_and_align_from_vtable(
&self,
- vtable: Pointer,
+ vtable: Pointer<M::PointerTag>,
) -> EvalResult<'tcx, (Size, Align)> {
let pointer_size = self.pointer_size();
let pointer_align = self.tcx.data_layout.pointer_align;
// except according to those terms.
use std::fmt::Write;
+use std::hash::Hash;
use syntax_pos::symbol::Symbol;
-use rustc::ty::layout::{self, Size, Primitive};
-use rustc::ty::{self, Ty};
+use rustc::ty::layout::{self, Size, Align, TyLayout};
+use rustc::ty;
use rustc_data_structures::fx::FxHashSet;
use rustc::mir::interpret::{
- Scalar, AllocType, EvalResult, EvalErrorKind, PointerArithmetic
+ Scalar, AllocType, EvalResult, EvalErrorKind
};
use super::{
- OpTy, Machine, EvalContext, ScalarMaybeUndef
+ ValTy, OpTy, MPlaceTy, Machine, EvalContext, ScalarMaybeUndef
};
-macro_rules! validation_failure{
+macro_rules! validation_failure {
($what:expr, $where:expr, $details:expr) => {{
let where_ = path_format($where);
let where_ = if where_.is_empty() {
}};
}
+macro_rules! try_validation {
+ ($e:expr, $what:expr, $where:expr, $details:expr) => {{
+ match $e {
+ Ok(x) => x,
+ Err(_) => return validation_failure!($what, $where, $details),
+ }
+ }};
+
+ ($e:expr, $what:expr, $where:expr) => {{
+ match $e {
+ Ok(x) => x,
+ Err(_) => return validation_failure!($what, $where),
+ }
+ }}
+}
+
/// We want to show a nice path to the invalid field for diagnotsics,
/// but avoid string operations in the happy case where no error happens.
/// So we track a `Vec<PathElem>` where `PathElem` contains all the data we
Tag,
}
+/// State for tracking recursive validation of references
+pub struct RefTracking<'tcx, Tag> {
+ pub seen: FxHashSet<(OpTy<'tcx, Tag>)>,
+ pub todo: Vec<(OpTy<'tcx, Tag>, Vec<PathElem>)>,
+}
+
+impl<'tcx, Tag: Copy+Eq+Hash> RefTracking<'tcx, Tag> {
+ pub fn new(op: OpTy<'tcx, Tag>) -> Self {
+ let mut ref_tracking = RefTracking {
+ seen: FxHashSet(),
+ todo: vec![(op, Vec::new())],
+ };
+ ref_tracking.seen.insert(op);
+ ref_tracking
+ }
+}
+
// Adding a Deref and making a copy of the path to be put into the queue
// always go together. This one does it with only new allocation.
fn path_clone_and_deref(path: &Vec<PathElem>) -> Vec<PathElem> {
out
}
+fn scalar_format<Tag>(value: ScalarMaybeUndef<Tag>) -> String {
+ match value {
+ ScalarMaybeUndef::Undef =>
+ "uninitialized bytes".to_owned(),
+ ScalarMaybeUndef::Scalar(Scalar::Ptr(_)) =>
+ "a pointer".to_owned(),
+ ScalarMaybeUndef::Scalar(Scalar::Bits { bits, .. }) =>
+ bits.to_string(),
+ }
+}
+
impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
- fn validate_scalar(
+ /// Make sure that `value` is valid for `ty`, *assuming* `ty` is a primitive type.
+ fn validate_primitive_type(
&self,
- value: ScalarMaybeUndef,
- size: Size,
- scalar: &layout::Scalar,
+ value: ValTy<'tcx, M::PointerTag>,
path: &Vec<PathElem>,
- ty: Ty,
+ ref_tracking: Option<&mut RefTracking<'tcx, M::PointerTag>>,
+ const_mode: bool,
) -> EvalResult<'tcx> {
- trace!("validate scalar: {:#?}, {:#?}, {:#?}, {}", value, size, scalar, ty);
- let (lo, hi) = scalar.valid_range.clone().into_inner();
-
- let value = match value {
- ScalarMaybeUndef::Scalar(scalar) => scalar,
- ScalarMaybeUndef::Undef => return validation_failure!("undefined bytes", path),
- };
-
- let bits = match value {
- Scalar::Bits { bits, size: value_size } => {
- assert_eq!(value_size as u64, size.bytes());
- bits
+ // Go over all the primitive types
+ let ty = value.layout.ty;
+ match ty.sty {
+ ty::Bool => {
+ let value = value.to_scalar_or_undef();
+ try_validation!(value.to_bool(),
+ scalar_format(value), path, "a boolean");
},
- Scalar::Ptr(_) => {
- match ty.sty {
- ty::Bool |
- ty::Char |
- ty::Float(_) |
- ty::Int(_) |
- ty::Uint(_) => {
- return validation_failure!(
- "a pointer",
- path,
- format!("the type {}", ty.sty)
- );
+ ty::Char => {
+ let value = value.to_scalar_or_undef();
+ try_validation!(value.to_char(),
+ scalar_format(value), path, "a valid unicode codepoint");
+ },
+ ty::Float(_) | ty::Int(_) | ty::Uint(_) => {
+ let size = value.layout.size;
+ let value = value.to_scalar_or_undef();
+ if const_mode {
+ // Integers/floats in CTFE: Must be scalar bits, pointers are dangerous
+ try_validation!(value.to_bits(size),
+ scalar_format(value), path, "initialized plain bits");
+ } else {
+ // At run-time, for now, we accept *anything* for these types, including
+ // undef. We should fix that, but let's start low.
+ }
+ }
+ _ if ty.is_box() || ty.is_region_ptr() || ty.is_unsafe_ptr() => {
+ // Handle fat pointers. We also check fat raw pointers,
+ // their metadata must be valid!
+ // This also checks that the ptr itself is initialized, which
+ // seems reasonable even for raw pointers.
+ let place = try_validation!(self.ref_to_mplace(value),
+ "undefined data in pointer", path);
+ // Check metadata early, for better diagnostics
+ if place.layout.is_unsized() {
+ let tail = self.tcx.struct_tail(place.layout.ty);
+ match tail.sty {
+ ty::Dynamic(..) => {
+ let vtable = try_validation!(place.meta.unwrap().to_ptr(),
+ "non-pointer vtable in fat pointer", path);
+ try_validation!(self.read_drop_type_from_vtable(vtable),
+ "invalid drop fn in vtable", path);
+ try_validation!(self.read_size_and_align_from_vtable(vtable),
+ "invalid size or align in vtable", path);
+ // FIXME: More checks for the vtable.
+ }
+ ty::Slice(..) | ty::Str => {
+ try_validation!(place.meta.unwrap().to_usize(self),
+ "non-integer slice length in fat pointer", path);
+ }
+ ty::Foreign(..) => {
+ // Unsized, but not fat.
+ }
+ _ =>
+ bug!("Unexpected unsized type tail: {:?}", tail),
}
- ty::RawPtr(_) |
- ty::Ref(_, _, _) |
- ty::FnPtr(_) => {}
- _ => { unreachable!(); }
}
+ // for safe ptrs, also check the ptr values itself
+ if !ty.is_unsafe_ptr() {
+ // Make sure this is non-NULL and aligned
+ let (size, align) = self.size_and_align_of(place.meta, place.layout)?;
+ match self.memory.check_align(place.ptr, align) {
+ Ok(_) => {},
+ Err(err) => match err.kind {
+ EvalErrorKind::InvalidNullPointerUsage =>
+ return validation_failure!("NULL reference", path),
+ EvalErrorKind::AlignmentCheckFailed { .. } =>
+ return validation_failure!("unaligned reference", path),
+ _ =>
+ return validation_failure!(
+ "dangling (deallocated) reference", path
+ ),
+ }
+ }
+ // non-ZST also have to be dereferencable
+ if size != Size::ZERO {
+ let ptr = try_validation!(place.ptr.to_ptr(),
+ "integer pointer in non-ZST reference", path);
+ if const_mode {
+ // Skip validation entirely for some external statics
+ let alloc_kind = self.tcx.alloc_map.lock().get(ptr.alloc_id);
+ if let Some(AllocType::Static(did)) = alloc_kind {
+ // `extern static` cannot be validated as they have no body.
+ // FIXME: Statics from other crates are also skipped.
+ // They might be checked at a different type, but for now we
+ // want to avoid recursing too deeply. This is not sound!
+ if !did.is_local() || self.tcx.is_foreign_item(did) {
+ return Ok(());
+ }
+ }
+ }
+ try_validation!(self.memory.check_bounds(ptr, size, false),
+ "dangling (not entirely in bounds) reference", path);
+ }
+ if let Some(ref_tracking) = ref_tracking {
+ // Check if we have encountered this pointer+layout combination
+ // before. Proceed recursively even for integer pointers, no
+ // reason to skip them! They are (recursively) valid for some ZST,
+ // but not for others (e.g. `!` is a ZST).
+ let op = place.into();
+ if ref_tracking.seen.insert(op) {
+ trace!("Recursing below ptr {:#?}", *op);
+ ref_tracking.todo.push((op, path_clone_and_deref(path)));
+ }
+ }
+ }
+ }
+ ty::FnPtr(_sig) => {
+ let value = value.to_scalar_or_undef();
+ let ptr = try_validation!(value.to_ptr(),
+ scalar_format(value), path, "a pointer");
+ let _fn = try_validation!(self.memory.get_fn(ptr),
+ scalar_format(value), path, "a function pointer");
+ // FIXME: Check if the signature matches
+ }
+ // This should be all the primitive types
+ ty::Never => bug!("Uninhabited type should have been catched earlier"),
+ _ => bug!("Unexpected primitive type {}", value.layout.ty)
+ }
+ Ok(())
+ }
- let ptr_size = self.pointer_size();
- let ptr_max = u128::max_value() >> (128 - ptr_size.bits());
- return if lo > hi {
- if lo - hi == 1 {
- // no gap, all values are ok
- Ok(())
- } else if hi < ptr_max || lo > 1 {
- let max = u128::max_value() >> (128 - size.bits());
- validation_failure!(
- "pointer",
- path,
- format!("something in the range {:?} or {:?}", 0..=lo, hi..=max)
- )
- } else {
- Ok(())
+ /// Make sure that `value` matches the
+ fn validate_scalar_layout(
+ &self,
+ value: ScalarMaybeUndef<M::PointerTag>,
+ size: Size,
+ path: &Vec<PathElem>,
+ layout: &layout::Scalar,
+ ) -> EvalResult<'tcx> {
+ let (lo, hi) = layout.valid_range.clone().into_inner();
+ let max_hi = u128::max_value() >> (128 - size.bits()); // as big as the size fits
+ assert!(hi <= max_hi);
+ if lo == 0 && hi == max_hi {
+ // Nothing to check
+ return Ok(());
+ }
+ // At least one value is excluded. Get the bits.
+ let value = try_validation!(value.not_undef(),
+ scalar_format(value), path, format!("something in the range {:?}", layout.valid_range));
+ let bits = match value {
+ Scalar::Ptr(ptr) => {
+ if lo == 1 && hi == max_hi {
+ // only NULL is not allowed.
+ // We can call `check_align` to check non-NULL-ness, but have to also look
+ // for function pointers.
+ let non_null =
+ self.memory.check_align(
+ Scalar::Ptr(ptr), Align::from_bytes(1, 1).unwrap()
+ ).is_ok() ||
+ self.memory.get_fn(ptr).is_ok();
+ if !non_null {
+ // could be NULL
+ return validation_failure!("a potentially NULL pointer", path);
}
- } else if hi < ptr_max || lo > 1 {
- validation_failure!(
- "pointer",
- path,
- format!("something in the range {:?}", scalar.valid_range)
- )
+ return Ok(());
} else {
- Ok(())
- };
- },
- };
-
- // char gets a special treatment, because its number space is not contiguous so `TyLayout`
- // has no special checks for chars
- match ty.sty {
- ty::Char => {
- debug_assert_eq!(size.bytes(), 4);
- if ::std::char::from_u32(bits as u32).is_none() {
+ // Conservatively, we reject, because the pointer *could* have this
+ // value.
return validation_failure!(
- "character",
+ "a pointer",
path,
- "a valid unicode codepoint"
+ format!(
+ "something that cannot possibly be outside the (wrapping) range {:?}",
+ layout.valid_range
+ )
);
}
}
- _ => {},
- }
-
+ Scalar::Bits { bits, size: value_size } => {
+ assert_eq!(value_size as u64, size.bytes());
+ bits
+ }
+ };
+ // Now compare. This is slightly subtle because this is a special "wrap-around" range.
use std::ops::RangeInclusive;
let in_range = |bound: RangeInclusive<u128>| bound.contains(&bits);
if lo > hi {
- if in_range(0..=hi) || in_range(lo..=u128::max_value()) {
+ // wrapping around
+ if in_range(0..=hi) || in_range(lo..=max_hi) {
Ok(())
} else {
validation_failure!(
bits,
path,
- format!("something in the range {:?} or {:?}", ..=hi, lo..)
+ format!("something in the range {:?} or {:?}", 0..=hi, lo..=max_hi)
)
}
} else {
- if in_range(scalar.valid_range.clone()) {
+ if in_range(layout.valid_range.clone()) {
Ok(())
} else {
validation_failure!(
bits,
path,
- format!("something in the range {:?}", scalar.valid_range)
+ if hi == max_hi {
+ format!("something greater or equal to {}", lo)
+ } else {
+ format!("something in the range {:?}", layout.valid_range)
+ }
)
}
}
}
- /// This function checks the data at `op`.
+ /// This function checks the data at `op`. `op` is assumed to cover valid memory if it
+ /// is an indirect operand.
/// It will error if the bits at the destination do not match the ones described by the layout.
/// The `path` may be pushed to, but the part that is present when the function
/// starts must not be changed!
+ ///
+ /// `ref_tracking` can be None to avoid recursive checking below references.
+ /// This also toggles between "run-time" (no recursion) and "compile-time" (with recursion)
+ /// validation (e.g., pointer values are fine in integers at runtime).
pub fn validate_operand(
&self,
- dest: OpTy<'tcx>,
+ dest: OpTy<'tcx, M::PointerTag>,
path: &mut Vec<PathElem>,
- seen: &mut FxHashSet<(OpTy<'tcx>)>,
- todo: &mut Vec<(OpTy<'tcx>, Vec<PathElem>)>,
+ mut ref_tracking: Option<&mut RefTracking<'tcx, M::PointerTag>>,
+ const_mode: bool,
) -> EvalResult<'tcx> {
- trace!("validate_operand: {:?}, {:#?}", *dest, dest.layout);
+ trace!("validate_operand: {:?}, {:?}", *dest, dest.layout.ty);
- // Find the right variant. We have to handle this as a prelude, not via
- // proper recursion with the new inner layout, to be able to later nicely
- // print the field names of the enum field that is being accessed.
- let (variant, dest) = match dest.layout.variants {
+ // If this is a multi-variant layout, we have find the right one and proceed with that.
+ // (No good reasoning to make this recursion, but it is equivalent to that.)
+ let dest = match dest.layout.variants {
layout::Variants::NicheFilling { .. } |
layout::Variants::Tagged { .. } => {
let variant = match self.read_discriminant(dest) {
),
}
};
- let inner_dest = self.operand_downcast(dest, variant)?;
// Put the variant projection onto the path, as a field
path.push(PathElem::Field(dest.layout.ty
.ty_adt_def()
.unwrap()
.variants[variant].name));
+ // Proceed with this variant
+ let dest = self.operand_downcast(dest, variant)?;
trace!("variant layout: {:#?}", dest.layout);
- (variant, inner_dest)
+ dest
},
- layout::Variants::Single { index } => {
- // Pre-processing for trait objects: Treat them at their real type.
- // (We do not do this for slices and strings: For slices it is not needed,
- // `mplace_array_fields` does the right thing, and for strings there is no
- // real type that would show the actual length.)
- let dest = match dest.layout.ty.sty {
- ty::Dynamic(..) => {
- let dest = dest.to_mem_place(); // immediate trait objects are not a thing
- match self.unpack_dyn_trait(dest) {
- Ok(res) => res.1.into(),
- Err(_) =>
- return validation_failure!(
- "invalid vtable in fat pointer", path
- ),
- }
- }
- _ => dest
- };
- (index, dest)
- }
+ layout::Variants::Single { .. } => dest,
};
- // Remember the length, in case we need to truncate
- let path_len = path.len();
+ // First thing, find the real type:
+ // If it is a trait object, switch to the actual type that was used to create it.
+ let dest = match dest.layout.ty.sty {
+ ty::Dynamic(..) => {
+ let dest = dest.to_mem_place(); // immediate trait objects are not a thing
+ self.unpack_dyn_trait(dest)?.1.into()
+ },
+ _ => dest
+ };
- // Validate all fields
- match dest.layout.fields {
- // primitives are unions with zero fields
- // We still check `layout.fields`, not `layout.abi`, because `layout.abi`
- // is `Scalar` for newtypes around scalars, but we want to descend through the
- // fields to get a proper `path`.
- layout::FieldPlacement::Union(0) => {
- match dest.layout.abi {
- // nothing to do, whatever the pointer points to, it is never going to be read
- layout::Abi::Uninhabited =>
- return validation_failure!("a value of an uninhabited type", path),
- // check that the scalar is a valid pointer or that its bit range matches the
- // expectation.
- layout::Abi::Scalar(ref scalar_layout) => {
- let size = scalar_layout.value.size(self);
- let value = match self.read_value(dest) {
- Ok(val) => val,
- Err(err) => match err.kind {
- EvalErrorKind::PointerOutOfBounds { .. } |
- EvalErrorKind::ReadUndefBytes(_) =>
- return validation_failure!(
- "uninitialized or out-of-bounds memory", path
- ),
- _ =>
- return validation_failure!(
- "unrepresentable data", path
- ),
- }
- };
- let scalar = value.to_scalar_or_undef();
- self.validate_scalar(scalar, size, scalar_layout, &path, dest.layout.ty)?;
- if scalar_layout.value == Primitive::Pointer {
- // ignore integer pointers, we can't reason about the final hardware
- if let Scalar::Ptr(ptr) = scalar.not_undef()? {
- let alloc_kind = self.tcx.alloc_map.lock().get(ptr.alloc_id);
- if let Some(AllocType::Static(did)) = alloc_kind {
- // statics from other crates are already checked.
- // extern statics cannot be validated as they have no body.
- if !did.is_local() || self.tcx.is_foreign_item(did) {
- return Ok(());
- }
- }
- if value.layout.ty.builtin_deref(false).is_some() {
- let ptr_op = self.ref_to_mplace(value)?.into();
- // we have not encountered this pointer+layout combination
- // before.
- if seen.insert(ptr_op) {
- trace!("Recursing below ptr {:#?}", *value);
- todo.push((ptr_op, path_clone_and_deref(path)));
- }
- }
- }
- }
- },
- _ => bug!("bad abi for FieldPlacement::Union(0): {:#?}", dest.layout.abi),
- }
+ // If this is a scalar, validate the scalar layout.
+ // Things can be aggregates and have scalar layout at the same time, and that
+ // is very relevant for `NonNull` and similar structs: We need to validate them
+ // at their scalar layout *before* descending into their fields.
+ // FIXME: We could avoid some redundant checks here. For newtypes wrapping
+ // scalars, we do the same check on every "level" (e.g. first we check
+ // MyNewtype and then the scalar in there).
+ match dest.layout.abi {
+ layout::Abi::Uninhabited =>
+ return validation_failure!("a value of an uninhabited type", path),
+ layout::Abi::Scalar(ref layout) => {
+ let value = try_validation!(self.read_scalar(dest),
+ "uninitialized or unrepresentable data", path);
+ self.validate_scalar_layout(value, dest.layout.size, &path, layout)?;
}
- layout::FieldPlacement::Union(_) => {
+ // FIXME: Should we do something for ScalarPair? Vector?
+ _ => {}
+ }
+
+ // Check primitive types. We do this after checking the scalar layout,
+ // just to have that done as well. Primitives can have varying layout,
+ // so we check them separately and before aggregate handling.
+ // It is CRITICAL that we get this check right, or we might be
+ // validating the wrong thing!
+ let primitive = match dest.layout.fields {
+ // Primitives appear as Union with 0 fields -- except for fat pointers.
+ layout::FieldPlacement::Union(0) => true,
+ _ => dest.layout.ty.builtin_deref(true).is_some(),
+ };
+ if primitive {
+ let value = try_validation!(self.read_value(dest),
+ "uninitialized or unrepresentable data", path);
+ return self.validate_primitive_type(
+ value,
+ &path,
+ ref_tracking,
+ const_mode,
+ );
+ }
+
+ // Validate all fields of compound data structures
+ let path_len = path.len(); // Remember the length, in case we need to truncate
+ match dest.layout.fields {
+ layout::FieldPlacement::Union(..) => {
// We can't check unions, their bits are allowed to be anything.
// The fields don't need to correspond to any bit pattern of the union's fields.
// See https://github.com/rust-lang/rust/issues/32836#issuecomment-406875389
},
- layout::FieldPlacement::Array { stride, .. } if !dest.layout.is_zst() => {
- let dest = dest.to_mem_place(); // non-ZST array/slice/str cannot be immediate
+ layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
+ // Go look at all the fields
+ for i in 0..offsets.len() {
+ let field = self.operand_field(dest, i as u64)?;
+ path.push(self.aggregate_field_path_elem(dest.layout, i));
+ self.validate_operand(
+ field,
+ path,
+ ref_tracking.as_mut().map(|r| &mut **r),
+ const_mode,
+ )?;
+ path.truncate(path_len);
+ }
+ }
+ layout::FieldPlacement::Array { stride, .. } => {
+ let dest = if dest.layout.is_zst() {
+ // it's a ZST, the memory content cannot matter
+ MPlaceTy::dangling(dest.layout, self)
+ } else {
+ // non-ZST array/slice/str cannot be immediate
+ dest.to_mem_place()
+ };
match dest.layout.ty.sty {
// Special handling for strings to verify UTF-8
ty::Str => {
- match self.read_str(dest) {
- Ok(_) => {},
- Err(err) => match err.kind {
- EvalErrorKind::PointerOutOfBounds { .. } |
- EvalErrorKind::ReadUndefBytes(_) =>
- // The error here looks slightly different than it does
- // for slices, because we do not report the index into the
- // str at which we are OOB.
- return validation_failure!(
- "uninitialized or out-of-bounds memory", path
- ),
- _ =>
- return validation_failure!(
- "non-UTF-8 data in str", path
- ),
- }
- }
+ try_validation!(self.read_str(dest),
+ "uninitialized or non-UTF-8 data in str", path);
}
// Special handling for arrays/slices of builtin integer types
ty::Array(tys, ..) | ty::Slice(tys) if {
"undefined bytes", path
)
},
- EvalErrorKind::PointerOutOfBounds { allocation_size, .. } => {
- // If the array access is out-of-bounds, the first
- // undefined access is the after the end of the array.
- let i = (allocation_size.bytes() * ty_size) as usize;
- path.push(PathElem::ArrayElem(i));
- },
- _ => (),
+ // Other errors shouldn't be possible
+ _ => return Err(err),
}
-
- return validation_failure!(
- "uninitialized or out-of-bounds memory", path
- )
}
}
},
for (i, field) in self.mplace_array_fields(dest)?.enumerate() {
let field = field?;
path.push(PathElem::ArrayElem(i));
- self.validate_operand(field.into(), path, seen, todo)?;
+ self.validate_operand(
+ field.into(),
+ path,
+ ref_tracking.as_mut().map(|r| &mut **r),
+ const_mode,
+ )?;
path.truncate(path_len);
}
}
}
},
- layout::FieldPlacement::Array { .. } => {
- // An empty array. Nothing to do.
- }
- layout::FieldPlacement::Arbitrary { ref offsets, .. } => {
- // Fat pointers are treated like pointers, not aggregates.
- if dest.layout.ty.builtin_deref(true).is_some() {
- // This is a fat pointer.
- let ptr = match self.read_value(dest.into())
- .and_then(|val| self.ref_to_mplace(val))
- {
- Ok(ptr) => ptr,
- Err(_) =>
- return validation_failure!(
- "undefined location or metadata in fat pointer", path
- ),
- };
- // check metadata early, for better diagnostics
- match self.tcx.struct_tail(ptr.layout.ty).sty {
- ty::Dynamic(..) => {
- match ptr.extra.unwrap().to_ptr() {
- Ok(_) => {},
- Err(_) =>
- return validation_failure!(
- "non-pointer vtable in fat pointer", path
- ),
- }
- // FIXME: More checks for the vtable.
- }
- ty::Slice(..) | ty::Str => {
- match ptr.extra.unwrap().to_usize(self) {
- Ok(_) => {},
- Err(_) =>
- return validation_failure!(
- "non-integer slice length in fat pointer", path
- ),
- }
- }
- _ =>
- bug!("Unexpected unsized type tail: {:?}",
- self.tcx.struct_tail(ptr.layout.ty)
- ),
- }
- // for safe ptrs, recursively check it
- if !dest.layout.ty.is_unsafe_ptr() {
- let ptr = ptr.into();
- if seen.insert(ptr) {
- trace!("Recursing below fat ptr {:?}", ptr);
- todo.push((ptr, path_clone_and_deref(path)));
- }
- }
- } else {
- // Not a pointer, perform regular aggregate handling below
- for i in 0..offsets.len() {
- let field = self.operand_field(dest, i as u64)?;
- path.push(self.aggregate_field_path_elem(dest.layout.ty, variant, i));
- self.validate_operand(field, path, seen, todo)?;
- path.truncate(path_len);
- }
- }
- }
}
Ok(())
}
- fn aggregate_field_path_elem(&self, ty: Ty<'tcx>, variant: usize, field: usize) -> PathElem {
- match ty.sty {
+ fn aggregate_field_path_elem(&self, layout: TyLayout<'tcx>, field: usize) -> PathElem {
+ match layout.ty.sty {
// generators and closures.
ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
- let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap();
- let freevar = self.tcx.with_freevars(node_id, |fv| fv[field]);
- PathElem::ClosureVar(self.tcx.hir.name(freevar.var_id()))
+ if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) {
+ let freevar = self.tcx.with_freevars(node_id, |fv| fv[field]);
+ PathElem::ClosureVar(self.tcx.hir.name(freevar.var_id()))
+ } else {
+ // The closure is not local, so we cannot get the name
+ PathElem::ClosureVar(Symbol::intern(&field.to_string()))
+ }
}
// tuples
// enums
ty::Adt(def, ..) if def.is_enum() => {
- let variant = &def.variants[variant];
+ let variant = match layout.variants {
+ layout::Variants::Single { index } => &def.variants[index],
+ _ => bug!("aggregate_field_path_elem: got enum but not in a specific variant"),
+ };
PathElem::Field(variant.fields[field].ident.name)
}
ty::Adt(def, _) => PathElem::Field(def.non_enum_variant().fields[field].ident.name),
// nothing else has an aggregate layout
- _ => bug!("aggregate_field_path_elem: got non-aggregate type {:?}", ty),
+ _ => bug!("aggregate_field_path_elem: got non-aggregate type {:?}", layout.ty),
}
}
}
}
Some(AllocType::Memory(alloc)) => {
trace!("collecting {:?} with {:#?}", alloc_id, alloc);
- for &inner in alloc.relocations.values() {
+ for &((), inner) in alloc.relocations.values() {
collect_miri(tcx, inner, output);
}
},
ConstValue::Scalar(Scalar::Ptr(ptr)) =>
collect_miri(tcx, ptr.alloc_id, output),
ConstValue::ByRef(_id, alloc, _offset) => {
- for &id in alloc.relocations.values() {
+ for &((), id) in alloc.relocations.values() {
collect_miri(tcx, id, output);
}
}
// FIXME: figure out the rules and start linting
| FunctionAbiMismatch(..)
| FunctionArgMismatch(..)
+ | FunctionRetMismatch(..)
| FunctionArgCountMismatch
// fine at runtime, might be a register address or sth
| ReadBytesAsPointer
}
/// Creates the relevant generic argument substitutions
- /// corresponding to a set of generic parameters.
- pub fn create_substs_for_generic_args<'a, 'b, A, P, I>(
+ /// corresponding to a set of generic parameters. This is a
+ /// rather complex little function. Let me try to explain the
+ /// role of each of its parameters:
+ ///
+ /// To start, we are given the `def_id` of the thing we are
+ /// creating the substitutions for, and a partial set of
+ /// substitutions `parent_substs`. In general, the substitutions
+ /// for an item begin with substitutions for all the "parents" of
+ /// that item -- so e.g. for a method it might include the
+ /// parameters from the impl.
+ ///
+ /// Therefore, the method begins by walking down these parents,
+ /// starting with the outermost parent and proceed inwards until
+ /// it reaches `def_id`. For each parent P, it will check `parent_substs`
+ /// first to see if the parent's substitutions are listed in there. If so,
+ /// we can append those and move on. Otherwise, it invokes the
+ /// three callback functions:
+ ///
+ /// - `args_for_def_id`: given the def-id P, supplies back the
+ /// generic arguments that were given to that parent from within
+ /// the path; so e.g. if you have `<T as Foo>::Bar`, the def-id
+ /// might refer to the trait `Foo`, and the arguments might be
+ /// `[T]`. The boolean value indicates whether to infer values
+ /// for arguments whose values were not explicitly provided.
+ /// - `provided_kind`: given the generic parameter and the value from `args_for_def_id`,
+ /// instantiate a `Kind`
+ /// - `inferred_kind`: if no parameter was provided, and inference is enabled, then
+ /// creates a suitable inference variable.
+ pub fn create_substs_for_generic_args<'a, 'b>(
tcx: TyCtxt<'a, 'gcx, 'tcx>,
def_id: DefId,
parent_substs: &[Kind<'tcx>],
has_self: bool,
self_ty: Option<Ty<'tcx>>,
- args_for_def_id: A,
- provided_kind: P,
- inferred_kind: I,
- ) -> &'tcx Substs<'tcx> where
- A: Fn(DefId) -> (Option<&'b GenericArgs>, bool),
- P: Fn(&GenericParamDef, &GenericArg) -> Kind<'tcx>,
- I: Fn(Option<&[Kind<'tcx>]>, &GenericParamDef, bool) -> Kind<'tcx>
- {
+ args_for_def_id: impl Fn(DefId) -> (Option<&'b GenericArgs>, bool),
+ provided_kind: impl Fn(&GenericParamDef, &GenericArg) -> Kind<'tcx>,
+ inferred_kind: impl Fn(Option<&[Kind<'tcx>]>, &GenericParamDef, bool) -> Kind<'tcx>,
+ ) -> &'tcx Substs<'tcx> {
// Collect the segments of the path: we need to substitute arguments
// for parameters throughout the entire path (wherever there are
// generic parameters).
};
if self.can_coerce(ref_ty, expected) {
if let Ok(src) = cm.span_to_snippet(sp) {
- let sugg_expr = match expr.node { // parenthesize if needed (Issue #46756)
+ let needs_parens = match expr.node {
+ // parenthesize if needed (Issue #46756)
hir::ExprKind::Cast(_, _) |
- hir::ExprKind::Binary(_, _, _) => format!("({})", src),
- _ => src,
+ hir::ExprKind::Binary(_, _, _) => true,
+ // parenthesize borrows of range literals (Issue #54505)
+ _ if self.is_range_literal(expr) => true,
+ _ => false,
};
+ let sugg_expr = if needs_parens {
+ format!("({})", src)
+ } else {
+ src
+ };
+
if let Some(sugg) = self.can_use_as_ref(expr) {
return Some(sugg);
}
None
}
+ /// This function checks if the specified expression is a built-in range literal.
+ /// (See: `LoweringContext::lower_expr()` in `src/librustc/hir/lowering.rs`).
+ fn is_range_literal(&self, expr: &hir::Expr) -> bool {
+ use hir::{Path, QPath, ExprKind, TyKind};
+
+ // We support `::std::ops::Range` and `::core::ops::Range` prefixes
+ let is_range_path = |path: &Path| {
+ let mut segs = path.segments.iter()
+ .map(|seg| seg.ident.as_str());
+
+ if let (Some(root), Some(std_core), Some(ops), Some(range), None) =
+ (segs.next(), segs.next(), segs.next(), segs.next(), segs.next())
+ {
+ // "{{root}}" is the equivalent of `::` prefix in Path
+ root == "{{root}}" && (std_core == "std" || std_core == "core")
+ && ops == "ops" && range.starts_with("Range")
+ } else {
+ false
+ }
+ };
+
+ let span_is_range_literal = |span: &Span| {
+ // Check whether a span corresponding to a range expression
+ // is a range literal, rather than an explicit struct or `new()` call.
+ let source_map = self.tcx.sess.source_map();
+ let end_point = source_map.end_point(*span);
+
+ if let Ok(end_string) = source_map.span_to_snippet(end_point) {
+ !(end_string.ends_with("}") || end_string.ends_with(")"))
+ } else {
+ false
+ }
+ };
+
+ match expr.node {
+ // All built-in range literals but `..=` and `..` desugar to Structs
+ ExprKind::Struct(QPath::Resolved(None, ref path), _, _) |
+ // `..` desugars to its struct path
+ ExprKind::Path(QPath::Resolved(None, ref path)) => {
+ return is_range_path(&path) && span_is_range_literal(&expr.span);
+ }
+
+ // `..=` desugars into `::std::ops::RangeInclusive::new(...)`
+ ExprKind::Call(ref func, _) => {
+ if let ExprKind::Path(QPath::TypeRelative(ref ty, ref segment)) = func.node {
+ if let TyKind::Path(QPath::Resolved(None, ref path)) = ty.node {
+ let call_to_new = segment.ident.as_str() == "new";
+
+ return is_range_path(&path) && span_is_range_literal(&expr.span)
+ && call_to_new;
+ }
+ }
+ }
+
+ _ => {}
+ }
+
+ false
+ }
+
pub fn check_for_cast(&self,
err: &mut DiagnosticBuilder<'tcx>,
expr: &hir::Expr,
/// occurred**, so that annotations like `Vec<_>` are preserved
/// properly.
pub fn write_user_substs_from_substs(&self, hir_id: hir::HirId, substs: &'tcx Substs<'tcx>) {
+ debug!(
+ "write_user_substs_from_substs({:?}, {:?}) in fcx {}",
+ hir_id,
+ substs,
+ self.tag(),
+ );
+
if !substs.is_noop() {
let user_substs = self.infcx.canonicalize_response(&substs);
debug!("instantiate_value_path: user_substs = {:?}", user_substs);
expected: Expectation<'tcx>,
needs: Needs
) -> Ty<'tcx> {
+ debug!(
+ "check_expr_kind(expr={:?}, expected={:?}, needs={:?})",
+ expr,
+ expected,
+ needs,
+ );
+
let tcx = self.tcx;
let id = expr.id;
match expr.node {
span: Span,
node_id: ast::NodeId)
-> (Ty<'tcx>, Def) {
- debug!("instantiate_value_path(path={:?}, def={:?}, node_id={})",
- segments,
- def,
- node_id);
+ debug!(
+ "instantiate_value_path(segments={:?}, self_ty={:?}, def={:?}, node_id={})",
+ segments,
+ self_ty,
+ def,
+ node_id,
+ );
let path_segs = self.def_ids_for_path_segments(segments, def);
let hir_id = self.tcx.hir.node_to_hir_id(node_id);
self.write_substs(hir_id, substs);
+ debug!(
+ "instantiate_value_path: id={:?} substs={:?}",
+ node_id,
+ substs,
+ );
self.write_user_substs_from_substs(hir_id, substs);
(ty_substituted, new_def)
// lldb-command:run
// lldb-command:print arg
-// lldb-check:[...]$0 = Struct<i32> { b: -1, b1: 0 }
+// lldbg-check:[...]$0 = Struct<i32> { b: -1, b1: 0 }
+// lldbr-check:(associated_types::Struct<i32>) arg = Struct<i32> { b: -1, b1: 0 }
// lldb-command:continue
// lldb-command:print inferred
-// lldb-check:[...]$1 = 1
+// lldbg-check:[...]$1 = 1
+// lldbr-check:(i64) inferred = 1
// lldb-command:print explicitly
-// lldb-check:[...]$2 = 1
+// lldbg-check:[...]$2 = 1
+// lldbr-check:(i64) explicitly = 1
// lldb-command:continue
// lldb-command:print arg
-// lldb-check:[...]$3 = 2
+// lldbg-check:[...]$3 = 2
+// lldbr-check:(i64) arg = 2
// lldb-command:continue
// lldb-command:print arg
-// lldb-check:[...]$4 = (4, 5)
+// lldbg-check:[...]$4 = (4, 5)
+// lldbr-check:((i32, i64)) arg = { = 4 = 5 }
// lldb-command:continue
// lldb-command:print a
-// lldb-check:[...]$5 = 6
+// lldbg-check:[...]$5 = 6
+// lldbr-check:(i32) a = 6
// lldb-command:print b
-// lldb-check:[...]$6 = 7
+// lldbg-check:[...]$6 = 7
+// lldbr-check:(i64) b = 7
// lldb-command:continue
// lldb-command:print a
-// lldb-check:[...]$7 = 8
+// lldbg-check:[...]$7 = 8
+// lldbr-check:(i64) a = 8
// lldb-command:print b
-// lldb-check:[...]$8 = 9
+// lldbg-check:[...]$8 = 9
+// lldbr-check:(i32) b = 9
// lldb-command:continue
#![allow(unused_variables)]
// lldb-command:run
// lldb-command:print b
-// lldb-check:[...]$0 = false
+// lldbg-check:[...]$0 = false
+// lldbr-check:(bool) b = false
// lldb-command:print i
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(isize) i = -1
-// NOTE: LLDB does not support 32bit chars
-// d ebugger:print (usize)(c)
-// c heck:$3 = 97
+// NOTE: only rust-enabled lldb supports 32bit chars
+// lldbr-command:print c
+// lldbr-check:(char) c = 'a'
// lldb-command:print i8
-// lldb-check:[...]$2 = 'D'
+// lldbg-check:[...]$2 = 'D'
+// lldbr-check:(i8) i8 = 68
// lldb-command:print i16
-// lldb-check:[...]$3 = -16
+// lldbg-check:[...]$3 = -16
+// lldbr-check:(i16) i16 = -16
// lldb-command:print i32
-// lldb-check:[...]$4 = -32
+// lldbg-check:[...]$4 = -32
+// lldbr-check:(i32) i32 = -32
// lldb-command:print i64
-// lldb-check:[...]$5 = -64
+// lldbg-check:[...]$5 = -64
+// lldbr-check:(i64) i64 = -64
// lldb-command:print u
-// lldb-check:[...]$6 = 1
+// lldbg-check:[...]$6 = 1
+// lldbr-check:(usize) u = 1
// lldb-command:print u8
-// lldb-check:[...]$7 = 'd'
+// lldbg-check:[...]$7 = 'd'
+// lldbr-check:(u8) u8 = 100
// lldb-command:print u16
-// lldb-check:[...]$8 = 16
+// lldbg-check:[...]$8 = 16
+// lldbr-check:(u16) u16 = 16
// lldb-command:print u32
-// lldb-check:[...]$9 = 32
+// lldbg-check:[...]$9 = 32
+// lldbr-check:(u32) u32 = 32
// lldb-command:print u64
-// lldb-check:[...]$10 = 64
+// lldbg-check:[...]$10 = 64
+// lldbr-check:(u64) u64 = 64
// lldb-command:print f32
-// lldb-check:[...]$11 = 2.5
+// lldbg-check:[...]$11 = 2.5
+// lldbr-check:(f32) f32 = 2.5
// lldb-command:print f64
-// lldb-check:[...]$12 = 3.5
+// lldbg-check:[...]$12 = 3.5
+// lldbr-check:(f64) f64 = 3.5
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print *bool_ref
-// lldb-check:[...]$0 = true
+// lldbg-check:[...]$0 = true
+// lldbr-check:(bool) *bool_ref = true
// lldb-command:print *int_ref
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(isize) *int_ref = -1
-// NOTE: lldb doesn't support 32bit chars at the moment
-// d ebugger:print *char_ref
-// c heck:[...]$x = 97
+// NOTE: only rust-enabled lldb supports 32bit chars
+// lldbr-command:print *char_ref
+// lldbr-check:(char) *char_ref = 'a'
// lldb-command:print *i8_ref
-// lldb-check:[...]$2 = 'D'
+// lldbg-check:[...]$2 = 'D'
+// lldbr-check:(i8) *i8_ref = 68
// lldb-command:print *i16_ref
-// lldb-check:[...]$3 = -16
+// lldbg-check:[...]$3 = -16
+// lldbr-check:(i16) *i16_ref = -16
// lldb-command:print *i32_ref
-// lldb-check:[...]$4 = -32
+// lldbg-check:[...]$4 = -32
+// lldbr-check:(i32) *i32_ref = -32
// lldb-command:print *i64_ref
-// lldb-check:[...]$5 = -64
+// lldbg-check:[...]$5 = -64
+// lldbr-check:(i64) *i64_ref = -64
// lldb-command:print *uint_ref
-// lldb-check:[...]$6 = 1
+// lldbg-check:[...]$6 = 1
+// lldbr-check:(usize) *uint_ref = 1
// lldb-command:print *u8_ref
-// lldb-check:[...]$7 = 'd'
+// lldbg-check:[...]$7 = 'd'
+// lldbr-check:(u8) *u8_ref = 100
// lldb-command:print *u16_ref
-// lldb-check:[...]$8 = 16
+// lldbg-check:[...]$8 = 16
+// lldbr-check:(u16) *u16_ref = 16
// lldb-command:print *u32_ref
-// lldb-check:[...]$9 = 32
+// lldbg-check:[...]$9 = 32
+// lldbr-check:(u32) *u32_ref = 32
// lldb-command:print *u64_ref
-// lldb-check:[...]$10 = 64
+// lldbg-check:[...]$10 = 64
+// lldbr-check:(u64) *u64_ref = 64
// lldb-command:print *f32_ref
-// lldb-check:[...]$11 = 2.5
+// lldbg-check:[...]$11 = 2.5
+// lldbr-check:(f32) *f32_ref = 2.5
// lldb-command:print *f64_ref
-// lldb-check:[...]$12 = 3.5
+// lldbg-check:[...]$12 = 3.5
+// lldbr-check:(f64) *f64_ref = 3.5
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print *the_a_ref
-// lldb-check:[...]$0 = TheA
+// lldbg-check:[...]$0 = TheA
+// lldbr-check:(borrowed_c_style_enum::ABC) *the_a_ref = borrowed_c_style_enum::ABC::TheA
// lldb-command:print *the_b_ref
-// lldb-check:[...]$1 = TheB
+// lldbg-check:[...]$1 = TheB
+// lldbr-check:(borrowed_c_style_enum::ABC) *the_b_ref = borrowed_c_style_enum::ABC::TheB
// lldb-command:print *the_c_ref
-// lldb-check:[...]$2 = TheC
+// lldbg-check:[...]$2 = TheC
+// lldbr-check:(borrowed_c_style_enum::ABC) *the_c_ref = borrowed_c_style_enum::ABC::TheC
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print *the_a_ref
-// lldb-check:[...]$0 = TheA { x: 0, y: 8970181431921507452 }
+// lldbg-check:[...]$0 = TheA { x: 0, y: 8970181431921507452 }
+// lldbr-check:(borrowed_enum::ABC::TheA) *the_a_ref = TheA { borrowed_enum::ABC::TheA: 0, borrowed_enum::ABC::TheB: 8970181431921507452 }
// lldb-command:print *the_b_ref
-// lldb-check:[...]$1 = TheB(0, 286331153, 286331153)
+// lldbg-check:[...]$1 = TheB(0, 286331153, 286331153)
+// lldbr-check:(borrowed_enum::ABC::TheB) *the_b_ref = { = 0 = 286331153 = 286331153 }
// lldb-command:print *univariant_ref
-// lldb-check:[...]$2 = TheOnlyCase(4820353753753434)
+// lldbg-check:[...]$2 = TheOnlyCase(4820353753753434)
+// lldbr-check:(borrowed_enum::Univariant) *univariant_ref = { borrowed_enum::TheOnlyCase = { = 4820353753753434 } }
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print *stack_val_ref
-// lldb-check:[...]$0 = SomeStruct { x: 10, y: 23.5 }
+// lldbg-check:[...]$0 = SomeStruct { x: 10, y: 23.5 }
+// lldbr-check:(borrowed_struct::SomeStruct) *stack_val_ref = SomeStruct { x: 10, y: 23.5 }
// lldb-command:print *stack_val_interior_ref_1
-// lldb-check:[...]$1 = 10
+// lldbg-check:[...]$1 = 10
+// lldbr-check:(isize) *stack_val_interior_ref_1 = 10
// lldb-command:print *stack_val_interior_ref_2
-// lldb-check:[...]$2 = 23.5
+// lldbg-check:[...]$2 = 23.5
+// lldbr-check:(f64) *stack_val_interior_ref_2 = 23.5
// lldb-command:print *ref_to_unnamed
-// lldb-check:[...]$3 = SomeStruct { x: 11, y: 24.5 }
+// lldbg-check:[...]$3 = SomeStruct { x: 11, y: 24.5 }
+// lldbr-check:(borrowed_struct::SomeStruct) *ref_to_unnamed = SomeStruct { x: 11, y: 24.5 }
// lldb-command:print *unique_val_ref
-// lldb-check:[...]$4 = SomeStruct { x: 13, y: 26.5 }
+// lldbg-check:[...]$4 = SomeStruct { x: 13, y: 26.5 }
+// lldbr-check:(borrowed_struct::SomeStruct) *unique_val_ref = SomeStruct { x: 13, y: 26.5 }
// lldb-command:print *unique_val_interior_ref_1
-// lldb-check:[...]$5 = 13
+// lldbg-check:[...]$5 = 13
+// lldbr-check:(isize) *unique_val_interior_ref_1 = 13
// lldb-command:print *unique_val_interior_ref_2
-// lldb-check:[...]$6 = 26.5
+// lldbg-check:[...]$6 = 26.5
+// lldbr-check:(f64) *unique_val_interior_ref_2 = 26.5
#![allow(unused_variables)]
#![feature(box_syntax)]
// lldb-command:run
// lldb-command:print *stack_val_ref
-// lldb-check:[...]$0 = (-14, -19)
+// lldbg-check:[...]$0 = (-14, -19)
+// lldbr-check:((i16, f32)) *stack_val_ref = { = -14 = -19 }
// lldb-command:print *ref_to_unnamed
-// lldb-check:[...]$1 = (-15, -20)
+// lldbg-check:[...]$1 = (-15, -20)
+// lldbr-check:((i16, f32)) *ref_to_unnamed = { = -15 = -20 }
// lldb-command:print *unique_val_ref
-// lldb-check:[...]$2 = (-17, -22)
+// lldbg-check:[...]$2 = (-17, -22)
+// lldbr-check:((i16, f32)) *unique_val_ref = { = -17 = -22 }
#![allow(unused_variables)]
// lldb-command:run
// lldb-command:print *bool_ref
-// lldb-check:[...]$0 = true
+// lldbg-check:[...]$0 = true
+// lldbr-check:(bool) *bool_ref = true
// lldb-command:print *int_ref
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(isize) *int_ref = -1
-// d ebugger:print *char_ref
-// c heck:[...]$3 = 97
+// NOTE: only rust-enabled lldb supports 32bit chars
+// lldbr-command:print *char_ref
+// lldbr-check:(char) *char_ref = 97
// lldb-command:print *i8_ref
-// lldb-check:[...]$2 = 68
+// lldbg-check:[...]$2 = 68
+// lldbr-check:(i8) *i8_ref = 68
// lldb-command:print *i16_ref
-// lldb-check:[...]$3 = -16
+// lldbg-check:[...]$3 = -16
+// lldbr-check:(i16) *i16_ref = -16
// lldb-command:print *i32_ref
-// lldb-check:[...]$4 = -32
+// lldbg-check:[...]$4 = -32
+// lldbr-check:(i32) *i32_ref = -32
// lldb-command:print *i64_ref
-// lldb-check:[...]$5 = -64
+// lldbg-check:[...]$5 = -64
+// lldbr-check:(i64) *i64_ref = -64
// lldb-command:print *uint_ref
-// lldb-check:[...]$6 = 1
+// lldbg-check:[...]$6 = 1
+// lldbr-check:(usize) *uint_ref = 1
// lldb-command:print *u8_ref
-// lldb-check:[...]$7 = 100
+// lldbg-check:[...]$7 = 100
+// lldbr-check:(u8) *u8_ref = 100
// lldb-command:print *u16_ref
-// lldb-check:[...]$8 = 16
+// lldbg-check:[...]$8 = 16
+// lldbr-check:(u16) *u16_ref = 16
// lldb-command:print *u32_ref
-// lldb-check:[...]$9 = 32
+// lldbg-check:[...]$9 = 32
+// lldbr-check:(u32) *u32_ref = 32
// lldb-command:print *u64_ref
-// lldb-check:[...]$10 = 64
+// lldbg-check:[...]$10 = 64
+// lldbr-check:(u64) *u64_ref = 64
// lldb-command:print *f32_ref
-// lldb-check:[...]$11 = 2.5
+// lldbg-check:[...]$11 = 2.5
+// lldbr-check:(f32) *f32_ref = 2.5
// lldb-command:print *f64_ref
-// lldb-check:[...]$12 = 3.5
+// lldbg-check:[...]$12 = 3.5
+// lldbr-check:(f64) *f64_ref = 3.5
#![allow(unused_variables)]
#![feature(box_syntax)]
// lldb-command:run
// lldb-command:print *a
-// lldb-check:[...]$0 = 1
+// lldbg-check:[...]$0 = 1
+// lldbr-check:(i32) *a = 1
// lldb-command:print *b
-// lldb-check:[...]$1 = (2, 3.5)
+// lldbg-check:[...]$1 = (2, 3.5)
+// lldbr-check:((i32, f64)) *b = { = 2 = 3.5 }
#![allow(unused_variables)]
#![feature(box_syntax)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-tidy-linelength
+
// min-lldb-version: 310
// compile-flags:-g
// lldb-command:run
// lldb-command:print *unique
-// lldb-check:[...]$0 = StructWithSomePadding { x: 99, y: 999, z: 9999, w: 99999 }
+// lldbg-check:[...]$0 = StructWithSomePadding { x: 99, y: 999, z: 9999, w: 99999 }
+// lldbr-check:(boxed_struct::StructWithSomePadding) *unique = StructWithSomePadding { x: 99, y: 999, z: 9999, w: 99999 }
// lldb-command:print *unique_dtor
-// lldb-check:[...]$1 = StructWithDestructor { x: 77, y: 777, z: 7777, w: 77777 }
+// lldbg-check:[...]$1 = StructWithDestructor { x: 77, y: 777, z: 7777, w: 77777 }
+// lldbr-check:(boxed_struct::StructWithDestructor) *unique_dtor = StructWithDestructor { x: 77, y: 777, z: 7777, w: 77777 }
#![allow(unused_variables)]
#![feature(box_syntax)]
// lldb-command:run
// lldb-command:print self
-// lldb-check:[...]$0 = 1111
+// lldbg-check:[...]$0 = 1111
+// lldbr-check:(isize) self = 1111
// lldb-command:continue
// lldb-command:print self
-// lldb-check:[...]$1 = Struct { x: 2222, y: 3333 }
+// lldbg-check:[...]$1 = Struct { x: 2222, y: 3333 }
+// lldbr-check:(by_value_self_argument_in_trait_impl::Struct) self = Struct { x: 2222, y: 3333 }
// lldb-command:continue
// lldb-command:print self
-// lldb-check:[...]$2 = (4444.5, 5555, 6666, 7777.5)
+// lldbg-check:[...]$2 = (4444.5, 5555, 6666, 7777.5)
+// lldbr-check:((f64, isize, isize, f64)) self = { = 4444.5 = 5555 = 6666 = 7777.5 }
// lldb-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print tuple_interior_padding
-// lldb-check:[...]$0 = (0, OneHundred)
+// lldbg-check:[...]$0 = (0, OneHundred)
+// lldbr-check:((i16, c_style_enum_in_composite::AnEnum)) tuple_interior_padding = { = 0 = c_style_enum_in_composite::AnEnum::OneHundred }
// lldb-command:print tuple_padding_at_end
-// lldb-check:[...]$1 = ((1, OneThousand), 2)
+// lldbg-check:[...]$1 = ((1, OneThousand), 2)
+// lldbr-check:(((u64, c_style_enum_in_composite::AnEnum), u64)) tuple_padding_at_end = { = { = 1 = c_style_enum_in_composite::AnEnum::OneThousand } = 2 }
// lldb-command:print tuple_different_enums
-// lldb-check:[...]$2 = (OneThousand, MountainView, OneMillion, Vienna)
+// lldbg-check:[...]$2 = (OneThousand, MountainView, OneMillion, Vienna)
+// lldbr-check:((c_style_enum_in_composite::AnEnum, c_style_enum_in_composite::AnotherEnum, c_style_enum_in_composite::AnEnum, c_style_enum_in_composite::AnotherEnum)) tuple_different_enums = { = c_style_enum_in_composite::AnEnum::OneThousand = c_style_enum_in_composite::AnotherEnum::MountainView = c_style_enum_in_composite::AnEnum::OneMillion = c_style_enum_in_composite::AnotherEnum::Vienna }
// lldb-command:print padded_struct
-// lldb-check:[...]$3 = PaddedStruct { a: 3, b: OneMillion, c: 4, d: Toronto, e: 5 }
+// lldbg-check:[...]$3 = PaddedStruct { a: 3, b: OneMillion, c: 4, d: Toronto, e: 5 }
+// lldbr-check:(c_style_enum_in_composite::PaddedStruct) padded_struct = PaddedStruct { a: 3, b: c_style_enum_in_composite::AnEnum::OneMillion, c: 4, d: c_style_enum_in_composite::AnotherEnum::Toronto, e: 5 }
// lldb-command:print packed_struct
-// lldb-check:[...]$4 = PackedStruct { a: 6, b: OneHundred, c: 7, d: Vienna, e: 8 }
+// lldbg-check:[...]$4 = PackedStruct { a: 6, b: OneHundred, c: 7, d: Vienna, e: 8 }
+// lldbr-check:(c_style_enum_in_composite::PackedStruct) packed_struct = PackedStruct { a: 6, b: c_style_enum_in_composite::AnEnum::OneHundred, c: 7, d: c_style_enum_in_composite::AnotherEnum::Vienna, e: 8 }
// lldb-command:print non_padded_struct
-// lldb-check:[...]$5 = NonPaddedStruct { a: OneMillion, b: MountainView, c: OneThousand, d: Toronto }
+// lldbg-check:[...]$5 = NonPaddedStruct { a: OneMillion, b: MountainView, c: OneThousand, d: Toronto }
+// lldbr-check:(c_style_enum_in_composite::NonPaddedStruct) non_padded_struct = NonPaddedStruct { a: c_style_enum_in_composite::AnEnum::OneMillion, b: c_style_enum_in_composite::AnotherEnum::MountainView, c: c_style_enum_in_composite::AnEnum::OneThousand, d: c_style_enum_in_composite::AnotherEnum::Toronto }
// lldb-command:print struct_with_drop
-// lldb-check:[...]$6 = (StructWithDrop { a: OneHundred, b: Vienna }, 9)
+// lldbg-check:[...]$6 = (StructWithDrop { a: OneHundred, b: Vienna }, 9)
+// lldbr-check:((c_style_enum_in_composite::StructWithDrop, i64)) struct_with_drop = { = StructWithDrop { a: c_style_enum_in_composite::AnEnum::OneHundred, b: c_style_enum_in_composite::AnotherEnum::Vienna } = 9 }
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-tidy-linelength
+
// ignore-aarch64
// ignore-gdb // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
// min-lldb-version: 310
// lldb-command:run
// lldb-command:print auto_one
-// lldb-check:[...]$0 = One
+// lldbg-check:[...]$0 = One
+// lldbr-check:(c_style_enum::AutoDiscriminant) auto_one = c_style_enum::AutoDiscriminant::One
// lldb-command:print auto_two
-// lldb-check:[...]$1 = Two
+// lldbg-check:[...]$1 = Two
+// lldbr-check:(c_style_enum::AutoDiscriminant) auto_two = c_style_enum::AutoDiscriminant::Two
// lldb-command:print auto_three
-// lldb-check:[...]$2 = Three
+// lldbg-check:[...]$2 = Three
+// lldbr-check:(c_style_enum::AutoDiscriminant) auto_three = c_style_enum::AutoDiscriminant::Three
// lldb-command:print manual_one_hundred
-// lldb-check:[...]$3 = OneHundred
+// lldbg-check:[...]$3 = OneHundred
+// lldbr-check:(c_style_enum::ManualDiscriminant) manual_one_hundred = c_style_enum::ManualDiscriminant::OneHundred
// lldb-command:print manual_one_thousand
-// lldb-check:[...]$4 = OneThousand
+// lldbg-check:[...]$4 = OneThousand
+// lldbr-check:(c_style_enum::ManualDiscriminant) manual_one_thousand = c_style_enum::ManualDiscriminant::OneThousand
// lldb-command:print manual_one_million
-// lldb-check:[...]$5 = OneMillion
+// lldbg-check:[...]$5 = OneMillion
+// lldbr-check:(c_style_enum::ManualDiscriminant) manual_one_million = c_style_enum::ManualDiscriminant::OneMillion
// lldb-command:print single_variant
-// lldb-check:[...]$6 = TheOnlyVariant
+// lldbg-check:[...]$6 = TheOnlyVariant
+// lldbr-check:(c_style_enum::SingleVariant) single_variant = c_style_enum::SingleVariant::TheOnlyVariant
#![allow(unused_variables)]
#![allow(dead_code)]
// lldb-command:run
// lldb-command:print x
-// lldb-check:[...]$0 = 0.5
+// lldbg-check:[...]$0 = 0.5
+// lldbr-check:(f64) x = 0.5
// lldb-command:print y
-// lldb-check:[...]$1 = 10
+// lldbg-check:[...]$1 = 10
+// lldbr-check:(i32) y = 10
// lldb-command:continue
// lldb-command:print *x
-// lldb-check:[...]$2 = 29
+// lldbg-check:[...]$2 = 29
+// lldbr-check:(i32) *x = 29
// lldb-command:print *y
-// lldb-check:[...]$3 = 110
+// lldbg-check:[...]$3 = 110
+// lldbr-check:(i32) *y = 110
// lldb-command:continue
#![feature(box_syntax)]
// lldb-command:run
// lldb-command:print result
-// lldb-check:[...]$0 = (17, 17)
+// lldbg-check:[...]$0 = (17, 17)
+// lldbr-check:((u32, u32)) result = { = 17 = 17 }
// lldb-command:print a_variable
-// lldb-check:[...]$1 = 123456789
+// lldbg-check:[...]$1 = 123456789
+// lldbr-check:(u32) a_variable = 123456789
// lldb-command:print another_variable
-// lldb-check:[...]$2 = 123456789.5
+// lldbg-check:[...]$2 = 123456789.5
+// lldbr-check:(f64) another_variable = 123456789.5
// lldb-command:continue
// lldb-command:print result
-// lldb-check:[...]$3 = (1212, 1212)
+// lldbg-check:[...]$3 = (1212, 1212)
+// lldbr-check:((i16, i16)) result = { = 1212 = 1212 }
// lldb-command:print a_variable
-// lldb-check:[...]$4 = 123456789
+// lldbg-check:[...]$4 = 123456789
+// lldbr-check:(u32) a_variable = 123456789
// lldb-command:print another_variable
-// lldb-check:[...]$5 = 123456789.5
+// lldbg-check:[...]$5 = 123456789.5
+// lldbr-check:(f64) another_variable = 123456789.5
// lldb-command:continue
// lldb-command:run
// lldb-command:print a
-// lldb-check:[...]$0 = 1
+// lldbg-check:[...]$0 = 1
+// lldbr-check:(isize) a = 1
// lldb-command:print b
-// lldb-check:[...]$1 = false
+// lldbg-check:[...]$1 = false
+// lldbr-check:(bool) b = false
// lldb-command:continue
// lldb-command:print a
-// lldb-check:[...]$2 = 2
+// lldbg-check:[...]$2 = 2
+// lldbr-check:(isize) a = 2
// lldb-command:print b
-// lldb-check:[...]$3 = 3
+// lldbg-check:[...]$3 = 3
+// lldbr-check:(u16) b = 3
// lldb-command:print c
-// lldb-check:[...]$4 = 4
+// lldbg-check:[...]$4 = 4
+// lldbr-check:(u16) c = 4
// lldb-command:continue
// lldb-command:print a
-// lldb-check:[...]$5 = 5
+// lldbg-check:[...]$5 = 5
+// lldbr-check:(isize) a = 5
// lldb-command:print b
-// lldb-check:[...]$6 = (6, 7)
+// lldbg-check:[...]$6 = (6, 7)
+// lldbr-check:((u32, u32)) b = { = 6 = 7 }
// lldb-command:continue
// lldb-command:print h
-// lldb-check:[...]$7 = 8
+// lldbg-check:[...]$7 = 8
+// lldbr-check:(i16) h = 8
// lldb-command:print i
-// lldb-check:[...]$8 = Struct { a: 9, b: 10 }
+// lldbg-check:[...]$8 = Struct { a: 9, b: 10 }
+// lldbr-check:(destructured_fn_argument::Struct) i = Struct { a: 9, b: 10 }
// lldb-command:print j
-// lldb-check:[...]$9 = 11
+// lldbg-check:[...]$9 = 11
+// lldbr-check:(i16) j = 11
// lldb-command:continue
// lldb-command:print k
-// lldb-check:[...]$10 = 12
+// lldbg-check:[...]$10 = 12
+// lldbr-check:(i64) k = 12
// lldb-command:print l
-// lldb-check:[...]$11 = 13
+// lldbg-check:[...]$11 = 13
+// lldbr-check:(i32) l = 13
// lldb-command:continue
// lldb-command:print m
-// lldb-check:[...]$12 = 14
+// lldbg-check:[...]$12 = 14
+// lldbr-check:(isize) m = 14
// lldb-command:print n
-// lldb-check:[...]$13 = 16
+// lldbg-check:[...]$13 = 16
+// lldbr-check:(i32) n = 16
// lldb-command:continue
// lldb-command:print o
-// lldb-check:[...]$14 = 18
+// lldbg-check:[...]$14 = 18
+// lldbr-check:(i32) o = 18
// lldb-command:continue
// lldb-command:print p
-// lldb-check:[...]$15 = 19
+// lldbg-check:[...]$15 = 19
+// lldbr-check:(i64) p = 19
// lldb-command:print q
-// lldb-check:[...]$16 = 20
+// lldbg-check:[...]$16 = 20
+// lldbr-check:(i32) q = 20
// lldb-command:print r
-// lldb-check:[...]$17 = Struct { a: 21, b: 22 }
+// lldbg-check:[...]$17 = Struct { a: 21, b: 22 }
+// lldbr-check:(destructured_fn_argument::Struct) r = Struct { a: 21, b: 22 }
// lldb-command:continue
// lldb-command:print s
-// lldb-check:[...]$18 = 24
+// lldbg-check:[...]$18 = 24
+// lldbr-check:(i32) s = 24
// lldb-command:print t
-// lldb-check:[...]$19 = 23
+// lldbg-check:[...]$19 = 23
+// lldbr-check:(i64) t = 23
// lldb-command:continue
// lldb-command:print u
-// lldb-check:[...]$20 = 25
+// lldbg-check:[...]$20 = 25
+// lldbr-check:(i16) u = 25
// lldb-command:print v
-// lldb-check:[...]$21 = 26
+// lldbg-check:[...]$21 = 26
+// lldbr-check:(i32) v = 26
// lldb-command:print w
-// lldb-check:[...]$22 = 27
+// lldbg-check:[...]$22 = 27
+// lldbr-check:(i64) w = 27
// lldb-command:print x
-// lldb-check:[...]$23 = 28
+// lldbg-check:[...]$23 = 28
+// lldbr-check:(i32) x = 28
// lldb-command:print y
-// lldb-check:[...]$24 = 29
+// lldbg-check:[...]$24 = 29
+// lldbr-check:(i64) y = 29
// lldb-command:print z
-// lldb-check:[...]$25 = 30
+// lldbg-check:[...]$25 = 30
+// lldbr-check:(i32) z = 30
// lldb-command:print ae
-// lldb-check:[...]$26 = 31
+// lldbg-check:[...]$26 = 31
+// lldbr-check:(i64) ae = 31
// lldb-command:print oe
-// lldb-check:[...]$27 = 32
+// lldbg-check:[...]$27 = 32
+// lldbr-check:(i32) oe = 32
// lldb-command:print ue
-// lldb-check:[...]$28 = 33
+// lldbg-check:[...]$28 = 33
+// lldbr-check:(u16) ue = 33
// lldb-command:continue
// lldb-command:print aa
-// lldb-check:[...]$29 = (34, 35)
+// lldbg-check:[...]$29 = (34, 35)
+// lldbr-check:((isize, isize)) aa = { = 34 = 35 }
// lldb-command:continue
// lldb-command:print bb
-// lldb-check:[...]$30 = (36, 37)
+// lldbg-check:[...]$30 = (36, 37)
+// lldbr-check:((isize, isize)) bb = { = 36 = 37 }
// lldb-command:continue
// lldb-command:print cc
-// lldb-check:[...]$31 = 38
+// lldbg-check:[...]$31 = 38
+// lldbr-check:(isize) cc = 38
// lldb-command:continue
// lldb-command:print dd
-// lldb-check:[...]$32 = (40, 41, 42)
+// lldbg-check:[...]$32 = (40, 41, 42)
+// lldbr-check:((isize, isize, isize)) dd = { = 40 = 41 = 42 }
// lldb-command:continue
// lldb-command:print *ee
-// lldb-check:[...]$33 = (43, 44, 45)
+// lldbg-check:[...]$33 = (43, 44, 45)
+// lldbr-check:((isize, isize, isize)) *ee = { = 43 = 44 = 45 }
// lldb-command:continue
// lldb-command:print *ff
-// lldb-check:[...]$34 = 46
+// lldbg-check:[...]$34 = 46
+// lldbr-check:(isize) *ff = 46
// lldb-command:print gg
-// lldb-check:[...]$35 = (47, 48)
+// lldbg-check:[...]$35 = (47, 48)
+// lldbr-check:((isize, isize)) gg = { = 47 = 48 }
// lldb-command:continue
// lldb-command:print *hh
-// lldb-check:[...]$36 = 50
+// lldbg-check:[...]$36 = 50
+// lldbr-check:(i32) *hh = 50
// lldb-command:continue
// lldb-command:print ii
-// lldb-check:[...]$37 = 51
+// lldbg-check:[...]$37 = 51
+// lldbr-check:(i32) ii = 51
// lldb-command:continue
// lldb-command:print *jj
-// lldb-check:[...]$38 = 52
+// lldbg-check:[...]$38 = 52
+// lldbr-check:(i32) *jj = 52
// lldb-command:continue
// lldb-command:print kk
-// lldb-check:[...]$39 = 53
+// lldbg-check:[...]$39 = 53
+// lldbr-check:(f64) kk = 53
// lldb-command:print ll
-// lldb-check:[...]$40 = 54
+// lldbg-check:[...]$40 = 54
+// lldbr-check:(isize) ll = 54
// lldb-command:continue
// lldb-command:print mm
-// lldb-check:[...]$41 = 55
+// lldbg-check:[...]$41 = 55
+// lldbr-check:(f64) mm = 55
// lldb-command:print *nn
-// lldb-check:[...]$42 = 56
+// lldbg-check:[...]$42 = 56
+// lldbr-check:(isize) *nn = 56
// lldb-command:continue
// lldb-command:print oo
-// lldb-check:[...]$43 = 57
+// lldbg-check:[...]$43 = 57
+// lldbr-check:(isize) oo = 57
// lldb-command:print pp
-// lldb-check:[...]$44 = 58
+// lldbg-check:[...]$44 = 58
+// lldbr-check:(isize) pp = 58
// lldb-command:print qq
-// lldb-check:[...]$45 = 59
+// lldbg-check:[...]$45 = 59
+// lldbr-check:(isize) qq = 59
// lldb-command:continue
// lldb-command:print rr
-// lldb-check:[...]$46 = 60
+// lldbg-check:[...]$46 = 60
+// lldbr-check:(isize) rr = 60
// lldb-command:print ss
-// lldb-check:[...]$47 = 61
+// lldbg-check:[...]$47 = 61
+// lldbr-check:(isize) ss = 61
// lldb-command:print tt
-// lldb-check:[...]$48 = 62
+// lldbg-check:[...]$48 = 62
+// lldbr-check:(isize) tt = 62
// lldb-command:continue
#![allow(unused_variables)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-tidy-linelength
+
// min-lldb-version: 310
// compile-flags:-g
// DESTRUCTURED STRUCT
// lldb-command:print x
-// lldb-check:[...]$0 = 400
+// lldbg-check:[...]$0 = 400
+// lldbr-check:(i16) x = 400
// lldb-command:print y
-// lldb-check:[...]$1 = 401.5
+// lldbg-check:[...]$1 = 401.5
+// lldbr-check:(f32) y = 401.5
// lldb-command:print z
-// lldb-check:[...]$2 = true
+// lldbg-check:[...]$2 = true
+// lldbr-check:(bool) z = true
// lldb-command:continue
// DESTRUCTURED TUPLE
// lldb-command:print _i8
-// lldb-check:[...]$3 = 0x6f
+// lldbg-check:[...]$3 = 0x6f
+// lldbr-check:(i8) _i8 = 111
// lldb-command:print _u8
-// lldb-check:[...]$4 = 0x70
+// lldbg-check:[...]$4 = 0x70
+// lldbr-check:(u8) _u8 = 112
// lldb-command:print _i16
-// lldb-check:[...]$5 = -113
+// lldbg-check:[...]$5 = -113
+// lldbr-check:(i16) _i16 = -113
// lldb-command:print _u16
-// lldb-check:[...]$6 = 114
+// lldbg-check:[...]$6 = 114
+// lldbr-check:(u16) _u16 = 114
// lldb-command:print _i32
-// lldb-check:[...]$7 = -115
+// lldbg-check:[...]$7 = -115
+// lldbr-check:(i32) _i32 = -115
// lldb-command:print _u32
-// lldb-check:[...]$8 = 116
+// lldbg-check:[...]$8 = 116
+// lldbr-check:(u32) _u32 = 116
// lldb-command:print _i64
-// lldb-check:[...]$9 = -117
+// lldbg-check:[...]$9 = -117
+// lldbr-check:(i64) _i64 = -117
// lldb-command:print _u64
-// lldb-check:[...]$10 = 118
+// lldbg-check:[...]$10 = 118
+// lldbr-check:(u64) _u64 = 118
// lldb-command:print _f32
-// lldb-check:[...]$11 = 119.5
+// lldbg-check:[...]$11 = 119.5
+// lldbr-check:(f32) _f32 = 119.5
// lldb-command:print _f64
-// lldb-check:[...]$12 = 120.5
+// lldbg-check:[...]$12 = 120.5
+// lldbr-check:(f64) _f64 = 120.5
// lldb-command:continue
// MORE COMPLEX CASE
// lldb-command:print v1
-// lldb-check:[...]$13 = 80000
+// lldbg-check:[...]$13 = 80000
+// lldbr-check:(i32) v1 = 80000
// lldb-command:print x1
-// lldb-check:[...]$14 = 8000
+// lldbg-check:[...]$14 = 8000
+// lldbr-check:(i16) x1 = 8000
// lldb-command:print *y1
-// lldb-check:[...]$15 = 80001.5
+// lldbg-check:[...]$15 = 80001.5
+// lldbr-check:(f32) *y1 = 80001.5
// lldb-command:print z1
-// lldb-check:[...]$16 = false
+// lldbg-check:[...]$16 = false
+// lldbr-check:(bool) z1 = false
// lldb-command:print *x2
-// lldb-check:[...]$17 = -30000
+// lldbg-check:[...]$17 = -30000
+// lldbr-check:(i16) *x2 = -30000
// lldb-command:print y2
-// lldb-check:[...]$18 = -300001.5
+// lldbg-check:[...]$18 = -300001.5
+// lldbr-check:(f32) y2 = -300001.5
// lldb-command:print *z2
-// lldb-check:[...]$19 = true
+// lldbg-check:[...]$19 = true
+// lldbr-check:(bool) *z2 = true
// lldb-command:print v2
-// lldb-check:[...]$20 = 854237.5
+// lldbg-check:[...]$20 = 854237.5
+// lldbr-check:(f64) v2 = 854237.5
// lldb-command:continue
// SIMPLE IDENTIFIER
// lldb-command:print i
-// lldb-check:[...]$21 = 1234
+// lldbg-check:[...]$21 = 1234
+// lldbr-check:(i32) i = 1234
// lldb-command:continue
// lldb-command:print simple_struct_ident
-// lldb-check:[...]$22 = Struct { x: 3537, y: 35437.5, z: true }
+// lldbg-check:[...]$22 = Struct { x: 3537, y: 35437.5, z: true }
+// lldbr-check:(destructured_for_loop_variable::Struct) simple_struct_ident = Struct { x: 3537, y: 35437.5, z: true }
// lldb-command:continue
// lldb-command:print simple_tuple_ident
-// lldb-check:[...]$23 = (34903493, 232323)
+// lldbg-check:[...]$23 = (34903493, 232323)
+// lldbr-check:((u32, i64)) simple_tuple_ident = { = 34903493 = 232323 }
// lldb-command:continue
#![allow(unused_variables)]
// lldb-command:run
// lldb-command:print a
-// lldb-check:[...]$0 = 1
+// lldbg-check:[...]$0 = 1
+// lldbr-check:(isize) a = 1
// lldb-command:print b
-// lldb-check:[...]$1 = false
+// lldbg-check:[...]$1 = false
+// lldbr-check:(bool) b = false
// lldb-command:print c
-// lldb-check:[...]$2 = 2
+// lldbg-check:[...]$2 = 2
+// lldbr-check:(isize) c = 2
// lldb-command:print d
-// lldb-check:[...]$3 = 3
+// lldbg-check:[...]$3 = 3
+// lldbr-check:(u16) d = 3
// lldb-command:print e
-// lldb-check:[...]$4 = 4
+// lldbg-check:[...]$4 = 4
+// lldbr-check:(u16) e = 4
// lldb-command:print f
-// lldb-check:[...]$5 = 5
+// lldbg-check:[...]$5 = 5
+// lldbr-check:(isize) f = 5
// lldb-command:print g
-// lldb-check:[...]$6 = (6, 7)
+// lldbg-check:[...]$6 = (6, 7)
+// lldbr-check:((u32, u32)) g = { = 6 = 7 }
// lldb-command:print h
-// lldb-check:[...]$7 = 8
+// lldbg-check:[...]$7 = 8
+// lldbr-check:(i16) h = 8
// lldb-command:print i
-// lldb-check:[...]$8 = Struct { a: 9, b: 10 }
+// lldbg-check:[...]$8 = Struct { a: 9, b: 10 }
+// lldbr-check:(destructured_local::Struct) i = Struct { a: 9, b: 10 }
// lldb-command:print j
-// lldb-check:[...]$9 = 11
+// lldbg-check:[...]$9 = 11
+// lldbr-check:(i16) j = 11
// lldb-command:print k
-// lldb-check:[...]$10 = 12
+// lldbg-check:[...]$10 = 12
+// lldbr-check:(i64) k = 12
// lldb-command:print l
-// lldb-check:[...]$11 = 13
+// lldbg-check:[...]$11 = 13
+// lldbr-check:(i32) l = 13
// lldb-command:print m
-// lldb-check:[...]$12 = 14
+// lldbg-check:[...]$12 = 14
+// lldbr-check:(i32) m = 14
// lldb-command:print n
-// lldb-check:[...]$13 = 16
+// lldbg-check:[...]$13 = 16
+// lldbr-check:(i32) n = 16
// lldb-command:print o
-// lldb-check:[...]$14 = 18
+// lldbg-check:[...]$14 = 18
+// lldbr-check:(i32) o = 18
// lldb-command:print p
-// lldb-check:[...]$15 = 19
+// lldbg-check:[...]$15 = 19
+// lldbr-check:(i64) p = 19
// lldb-command:print q
-// lldb-check:[...]$16 = 20
+// lldbg-check:[...]$16 = 20
+// lldbr-check:(i32) q = 20
// lldb-command:print r
-// lldb-check:[...]$17 = Struct { a: 21, b: 22 }
+// lldbg-check:[...]$17 = Struct { a: 21, b: 22 }
+// lldbr-check:(destructured_local::Struct) r = Struct { a: 21, b: 22 }
// lldb-command:print s
-// lldb-check:[...]$18 = 24
+// lldbg-check:[...]$18 = 24
+// lldbr-check:(i32) s = 24
// lldb-command:print t
-// lldb-check:[...]$19 = 23
+// lldbg-check:[...]$19 = 23
+// lldbr-check:(i64) t = 23
// lldb-command:print u
-// lldb-check:[...]$20 = 25
+// lldbg-check:[...]$20 = 25
+// lldbr-check:(i32) u = 25
// lldb-command:print v
-// lldb-check:[...]$21 = 26
+// lldbg-check:[...]$21 = 26
+// lldbr-check:(i32) v = 26
// lldb-command:print w
-// lldb-check:[...]$22 = 27
+// lldbg-check:[...]$22 = 27
+// lldbr-check:(i32) w = 27
// lldb-command:print x
-// lldb-check:[...]$23 = 28
+// lldbg-check:[...]$23 = 28
+// lldbr-check:(i32) x = 28
// lldb-command:print y
-// lldb-check:[...]$24 = 29
+// lldbg-check:[...]$24 = 29
+// lldbr-check:(i64) y = 29
// lldb-command:print z
-// lldb-check:[...]$25 = 30
+// lldbg-check:[...]$25 = 30
+// lldbr-check:(i32) z = 30
// lldb-command:print ae
-// lldb-check:[...]$26 = 31
+// lldbg-check:[...]$26 = 31
+// lldbr-check:(i64) ae = 31
// lldb-command:print oe
-// lldb-check:[...]$27 = 32
+// lldbg-check:[...]$27 = 32
+// lldbr-check:(i32) oe = 32
// lldb-command:print ue
-// lldb-check:[...]$28 = 33
+// lldbg-check:[...]$28 = 33
+// lldbr-check:(i32) ue = 33
// lldb-command:print aa
-// lldb-check:[...]$29 = (34, 35)
+// lldbg-check:[...]$29 = (34, 35)
+// lldbr-check:((i32, i32)) aa = { = 34 = 35 }
// lldb-command:print bb
-// lldb-check:[...]$30 = (36, 37)
+// lldbg-check:[...]$30 = (36, 37)
+// lldbr-check:((i32, i32)) bb = { = 36 = 37 }
// lldb-command:print cc
-// lldb-check:[...]$31 = 38
+// lldbg-check:[...]$31 = 38
+// lldbr-check:(i32) cc = 38
// lldb-command:print dd
-// lldb-check:[...]$32 = (40, 41, 42)
+// lldbg-check:[...]$32 = (40, 41, 42)
+// lldbr-check:((i32, i32, i32)) dd = { = 40 = 41 = 42 }
// lldb-command:print *ee
-// lldb-check:[...]$33 = (43, 44, 45)
+// lldbg-check:[...]$33 = (43, 44, 45)
+// lldbr-check:((i32, i32, i32)) *ee = { = 43 = 44 = 45 }
// lldb-command:print *ff
-// lldb-check:[...]$34 = 46
+// lldbg-check:[...]$34 = 46
+// lldbr-check:(i32) *ff = 46
// lldb-command:print gg
-// lldb-check:[...]$35 = (47, 48)
+// lldbg-check:[...]$35 = (47, 48)
+// lldbr-check:((i32, i32)) gg = { = 47 = 48 }
// lldb-command:print *hh
-// lldb-check:[...]$36 = 50
+// lldbg-check:[...]$36 = 50
+// lldbr-check:(i32) *hh = 50
// lldb-command:print ii
-// lldb-check:[...]$37 = 51
+// lldbg-check:[...]$37 = 51
+// lldbr-check:(i32) ii = 51
// lldb-command:print *jj
-// lldb-check:[...]$38 = 52
+// lldbg-check:[...]$38 = 52
+// lldbr-check:(i32) *jj = 52
// lldb-command:print kk
-// lldb-check:[...]$39 = 53
+// lldbg-check:[...]$39 = 53
+// lldbr-check:(f64) kk = 53
// lldb-command:print ll
-// lldb-check:[...]$40 = 54
+// lldbg-check:[...]$40 = 54
+// lldbr-check:(isize) ll = 54
// lldb-command:print mm
-// lldb-check:[...]$41 = 55
+// lldbg-check:[...]$41 = 55
+// lldbr-check:(f64) mm = 55
// lldb-command:print *nn
-// lldb-check:[...]$42 = 56
+// lldbg-check:[...]$42 = 56
+// lldbr-check:(isize) *nn = 56
#![allow(unused_variables)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-tidy-linelength
+
// min-lldb-version: 310
// compile-flags:-g
// lldb-command:run
// lldb-command:print no_padding1
-// lldb-check:[...]$0 = NoPadding1 { x: [0, 1, 2], y: -3, z: [4.5, 5.5] }
+// lldbg-check:[...]$0 = NoPadding1 { x: [0, 1, 2], y: -3, z: [4.5, 5.5] }
+// lldbr-check:(evec_in_struct::NoPadding1) no_padding1 = NoPadding1 { x: [0, 1, 2], y: -3, z: [4.5, 5.5] }
// lldb-command:print no_padding2
-// lldb-check:[...]$1 = NoPadding2 { x: [6, 7, 8], y: [[9, 10], [11, 12]] }
+// lldbg-check:[...]$1 = NoPadding2 { x: [6, 7, 8], y: [[9, 10], [11, 12]] }
+// lldbr-check:(evec_in_struct::NoPadding2) no_padding2 = NoPadding2 { x: [6, 7, 8], y: [[9, 10], [11, 12]] }
// lldb-command:print struct_internal_padding
-// lldb-check:[...]$2 = StructInternalPadding { x: [13, 14], y: [15, 16] }
+// lldbg-check:[...]$2 = StructInternalPadding { x: [13, 14], y: [15, 16] }
+// lldbr-check:(evec_in_struct::StructInternalPadding) struct_internal_padding = StructInternalPadding { x: [13, 14], y: [15, 16] }
// lldb-command:print single_vec
-// lldb-check:[...]$3 = SingleVec { x: [17, 18, 19, 20, 21] }
+// lldbg-check:[...]$3 = SingleVec { x: [17, 18, 19, 20, 21] }
+// lldbr-check:(evec_in_struct::SingleVec) single_vec = SingleVec { x: [17, 18, 19, 20, 21] }
// lldb-command:print struct_padded_at_end
-// lldb-check:[...]$4 = StructPaddedAtEnd { x: [22, 23], y: [24, 25] }
+// lldbg-check:[...]$4 = StructPaddedAtEnd { x: [22, 23], y: [24, 25] }
+// lldbr-check:(evec_in_struct::StructPaddedAtEnd) struct_padded_at_end = StructPaddedAtEnd { x: [22, 23], y: [24, 25] }
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print len
-// lldb-check:[...]$0 = 20
+// lldbg-check:[...]$0 = 20
+// lldbr-check:(i32) len = 20
// lldb-command:print local0
-// lldb-check:[...]$1 = 19
+// lldbg-check:[...]$1 = 19
+// lldbr-check:(i32) local0 = 19
// lldb-command:print local1
-// lldb-check:[...]$2 = true
+// lldbg-check:[...]$2 = true
+// lldbr-check:(bool) local1 = true
// lldb-command:print local2
-// lldb-check:[...]$3 = 20.5
+// lldbg-check:[...]$3 = 20.5
+// lldbr-check:(f64) local2 = 20.5
// lldb-command:continue
// lldb-command:run
// lldb-command:print x
-// lldb-check:[...]$0 = 111102
+// lldbg-check:[...]$0 = 111102
+// lldbr-check:(isize) x = 111102
// lldb-command:print y
-// lldb-check:[...]$1 = true
+// lldbg-check:[...]$1 = true
+// lldbr-check:(bool) y = true
// lldb-command:continue
// lldb-command:print a
-// lldb-check:[...]$2 = 2000
+// lldbg-check:[...]$2 = 2000
+// lldbr-check:(i32) a = 2000
// lldb-command:print b
-// lldb-check:[...]$3 = 3000
+// lldbg-check:[...]$3 = 3000
+// lldbr-check:(i64) b = 3000
// lldb-command:continue
// lldb-command:run
// lldb-command:print *t0
-// lldb-check:[...]$0 = 1
+// lldbg-check:[...]$0 = 1
+// lldbr-check:(i32) *t0 = 1
// lldb-command:print *t1
-// lldb-check:[...]$1 = 2.5
+// lldbg-check:[...]$1 = 2.5
+// lldbr-check:(f64) *t1 = 2.5
// lldb-command:print ret
-// lldb-check:[...]$2 = ((1, 2.5), (2.5, 1))
+// lldbg-check:[...]$2 = ((1, 2.5), (2.5, 1))
+// lldbr-check:(((i32, f64), (f64, i32))) ret = { = { = 1 = 2.5 } = { = 2.5 = 1 } }
// lldb-command:continue
// lldb-command:print *t0
-// lldb-check:[...]$3 = 3.5
+// lldbg-check:[...]$3 = 3.5
+// lldbr-check:(f64) *t0 = 3.5
// lldb-command:print *t1
-// lldb-check:[...]$4 = 4
+// lldbg-check:[...]$4 = 4
+// lldbr-check:(u16) *t1 = 4
// lldb-command:print ret
-// lldb-check:[...]$5 = ((3.5, 4), (4, 3.5))
+// lldbg-check:[...]$5 = ((3.5, 4), (4, 3.5))
+// lldbr-check:(((f64, u16), (u16, f64))) ret = { = { = 3.5 = 4 } = { = 4 = 3.5 } }
// lldb-command:continue
// lldb-command:print *t0
-// lldb-check:[...]$6 = 5
+// lldbg-check:[...]$6 = 5
+// lldbr-check:(i32) *t0 = 5
// lldb-command:print *t1
-// lldb-check:[...]$7 = Struct { a: 6, b: 7.5 }
+// lldbg-check:[...]$7 = Struct { a: 6, b: 7.5 }
+// lldbr-check:(generic_function::Struct) *t1 = Struct { a: 6, b: 7.5 }
// lldb-command:print ret
-// lldb-check:[...]$8 = ((5, Struct { a: 6, b: 7.5 }), (Struct { a: 6, b: 7.5 }, 5))
+// lldbg-check:[...]$8 = ((5, Struct { a: 6, b: 7.5 }), (Struct { a: 6, b: 7.5 }, 5))
+// lldbr-check:(((i32, generic_function::Struct), (generic_function::Struct, i32))) ret = { = { = 5 = Struct { a: 6, b: 7.5 } } = { = Struct { a: 6, b: 7.5 } = 5 } }
// lldb-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print x
-// lldb-check:[...]$0 = -1
+// lldbg-check:[...]$0 = -1
+// lldbr-check:(i32) x = -1
// lldb-command:print y
-// lldb-check:[...]$1 = 1
+// lldbg-check:[...]$1 = 1
+// lldbr-check:(i32) y = 1
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$2 = -1
+// lldbg-check:[...]$2 = -1
+// lldbr-check:(i32) x = -1
// lldb-command:print y
-// lldb-check:[...]$3 = 2.5
+// lldbg-check:[...]$3 = 2.5
+// lldbr-check:(f64) y = 2.5
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$4 = -2.5
+// lldbg-check:[...]$4 = -2.5
+// lldbr-check:(f64) x = -2.5
// lldb-command:print y
-// lldb-check:[...]$5 = 1
+// lldbg-check:[...]$5 = 1
+// lldbr-check:(i32) y = 1
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$6 = -2.5
+// lldbg-check:[...]$6 = -2.5
+// lldbr-check:(f64) x = -2.5
// lldb-command:print y
-// lldb-check:[...]$7 = 2.5
+// lldbg-check:[...]$7 = 2.5
+// lldbr-check:(f64) y = 2.5
// lldb-command:continue
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-tidy-linelength
// compile-flags:-g
// min-lldb-version: 310
// STACK BY REF
// lldb-command:print *self
-// lldb-check:[...]$0 = Struct<(u32, i32)> { x: (8888, -8888) }
+// lldbg-check:[...]$0 = Struct<(u32, i32)> { x: (8888, -8888) }
+// lldbr-check:(generic_method_on_generic_struct::Struct<(u32, i32)>) *self = { x = { = 8888 = -8888 } }
// lldb-command:print arg1
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(isize) arg1 = -1
// lldb-command:print arg2
-// lldb-check:[...]$2 = 2
+// lldbg-check:[...]$2 = 2
+// lldbr-check:(u16) arg2 = 2
// lldb-command:continue
// STACK BY VAL
// lldb-command:print self
-// lldb-check:[...]$3 = Struct<(u32, i32)> { x: (8888, -8888) }
+// lldbg-check:[...]$3 = Struct<(u32, i32)> { x: (8888, -8888) }
+// lldbr-check:(generic_method_on_generic_struct::Struct<(u32, i32)>) self = { x = { = 8888 = -8888 } }
// lldb-command:print arg1
-// lldb-check:[...]$4 = -3
+// lldbg-check:[...]$4 = -3
+// lldbr-check:(isize) arg1 = -3
// lldb-command:print arg2
-// lldb-check:[...]$5 = -4
+// lldbg-check:[...]$5 = -4
+// lldbr-check:(i16) arg2 = -4
// lldb-command:continue
// OWNED BY REF
// lldb-command:print *self
-// lldb-check:[...]$6 = Struct<f64> { x: 1234.5 }
+// lldbg-check:[...]$6 = Struct<f64> { x: 1234.5 }
+// lldbr-check:(generic_method_on_generic_struct::Struct<f64>) *self = Struct<f64> { x: 1234.5 }
// lldb-command:print arg1
-// lldb-check:[...]$7 = -5
+// lldbg-check:[...]$7 = -5
+// lldbr-check:(isize) arg1 = -5
// lldb-command:print arg2
-// lldb-check:[...]$8 = -6
+// lldbg-check:[...]$8 = -6
+// lldbr-check:(i32) arg2 = -6
// lldb-command:continue
// OWNED BY VAL
// lldb-command:print self
-// lldb-check:[...]$9 = Struct<f64> { x: 1234.5 }
+// lldbg-check:[...]$9 = Struct<f64> { x: 1234.5 }
+// lldbr-check:(generic_method_on_generic_struct::Struct<f64>) self = Struct<f64> { x: 1234.5 }
// lldb-command:print arg1
-// lldb-check:[...]$10 = -7
+// lldbg-check:[...]$10 = -7
+// lldbr-check:(isize) arg1 = -7
// lldb-command:print arg2
-// lldb-check:[...]$11 = -8
+// lldbg-check:[...]$11 = -8
+// lldbr-check:(i64) arg2 = -8
// lldb-command:continue
// OWNED MOVED
// lldb-command:print *self
-// lldb-check:[...]$12 = Struct<f64> { x: 1234.5 }
+// lldbg-check:[...]$12 = Struct<f64> { x: 1234.5 }
+// lldbr-check:(generic_method_on_generic_struct::Struct<f64>) *self = Struct<f64> { x: 1234.5 }
// lldb-command:print arg1
-// lldb-check:[...]$13 = -9
+// lldbg-check:[...]$13 = -9
+// lldbr-check:(isize) arg1 = -9
// lldb-command:print arg2
-// lldb-check:[...]$14 = -10.5
+// lldbg-check:[...]$14 = -10.5
+// lldbr-check:(f32) arg2 = -10.5
// lldb-command:continue
#![feature(box_syntax)]
// lldb-command:run
// lldb-command:print int_int
-// lldb-check:[...]$0 = AGenericStruct<i32, i32> { key: 0, value: 1 }
+// lldbg-check:[...]$0 = AGenericStruct<i32, i32> { key: 0, value: 1 }
+// lldbr-check:(generic_struct::AGenericStruct<i32, i32>) int_int = AGenericStruct<i32, i32> { key: 0, value: 1 }
// lldb-command:print int_float
-// lldb-check:[...]$1 = AGenericStruct<i32, f64> { key: 2, value: 3.5 }
+// lldbg-check:[...]$1 = AGenericStruct<i32, f64> { key: 2, value: 3.5 }
+// lldbr-check:(generic_struct::AGenericStruct<i32, f64>) int_float = AGenericStruct<i32, f64> { key: 2, value: 3.5 }
// lldb-command:print float_int
-// lldb-check:[...]$2 = AGenericStruct<f64, i32> { key: 4.5, value: 5 }
+// lldbg-check:[...]$2 = AGenericStruct<f64, i32> { key: 4.5, value: 5 }
+// lldbr-check:(generic_struct::AGenericStruct<f64, i32>) float_int = AGenericStruct<f64, i32> { key: 4.5, value: 5 }
// lldb-command:print float_int_float
-// lldb-check:[...]$3 = AGenericStruct<f64, generic_struct::AGenericStruct<i32, f64>> { key: 6.5, value: AGenericStruct<i32, f64> { key: 7, value: 8.5 } }
+// lldbg-check:[...]$3 = AGenericStruct<f64, generic_struct::AGenericStruct<i32, f64>> { key: 6.5, value: AGenericStruct<i32, f64> { key: 7, value: 8.5 } }
+// lldbr-check:(generic_struct::AGenericStruct<f64, generic_struct::AGenericStruct<i32, f64>>) float_int_float = AGenericStruct<f64, generic_struct::AGenericStruct<i32, f64>> { key: 6.5, value: AGenericStruct<i32, f64> { key: 7, value: 8.5 } }
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print case1
-// lldb-check:[...]$0 = Case1(0, 31868, 31868, 31868, 31868)
+// lldbg-check:[...]$0 = Case1(0, 31868, 31868, 31868, 31868)
+// lldbr-check:(generic_tuple_style_enum::Regular<u16, u32, u64>::Case1) case1 = { = 0 = 31868 = 31868 = 31868 = 31868 }
// lldb-command:print case2
-// lldb-check:[...]$1 = Case2(0, 286331153, 286331153)
+// lldbg-check:[...]$1 = Case2(0, 286331153, 286331153)
+// lldbr-check:(generic_tuple_style_enum::Regular<i16, i32, i64>::Case2) case2 = Regular<i16, i32, i64>::Case2 { generic_tuple_style_enum::Regular<i16, i32, i64>::Case1: 0, generic_tuple_style_enum::Regular<i16, i32, i64>::Case2: 286331153, generic_tuple_style_enum::Regular<i16, i32, i64>::Case3: 286331153 }
// lldb-command:print case3
-// lldb-check:[...]$2 = Case3(0, 6438275382588823897)
+// lldbg-check:[...]$2 = Case3(0, 6438275382588823897)
+// lldbr-check:(generic_tuple_style_enum::Regular<i16, i32, i64>::Case3) case3 = Regular<i16, i32, i64>::Case3 { generic_tuple_style_enum::Regular<i16, i32, i64>::Case1: 0, generic_tuple_style_enum::Regular<i16, i32, i64>::Case2: 6438275382588823897 }
// lldb-command:print univariant
-// lldb-check:[...]$3 = TheOnlyCase(-1)
+// lldbg-check:[...]$3 = TheOnlyCase(-1)
+// lldbr-check:(generic_tuple_style_enum::Univariant<i64>) univariant = { generic_tuple_style_enum::TheOnlyCase = { = -1 } }
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
// lldb-command:run
// lldb-command:print string1.length
-// lldb-check:[...]$0 = 48
+// lldbg-check:[...]$0 = 48
+// lldbr-check:(usize) length = 48
// lldb-command:print string2.length
-// lldb-check:[...]$1 = 49
+// lldbg-check:[...]$1 = 49
+// lldbr-check:(usize) length = 49
// lldb-command:print string3.length
-// lldb-check:[...]$2 = 50
+// lldbg-check:[...]$2 = 50
+// lldbr-check:(usize) length = 50
// lldb-command:continue
// lldb-command:run
// lldb-command:print v
-// lldb-check:[...]$0 = vec![1, 2, 3]
+// lldbg-check:[...]$0 = vec![1, 2, 3]
+// lldbr-check:(alloc::vec::Vec<i32>) v = vec![1, 2, 3]
// lldb-command:print zs
-// lldb-check:[...]$1 = StructWithZeroSizedField { x: ZeroSizedStruct, y: 123, z: ZeroSizedStruct, w: 456 }
-// lldb-command:continue
+// lldbg-check:[...]$1 = StructWithZeroSizedField { x: ZeroSizedStruct, y: 123, z: ZeroSizedStruct, w: 456 }
+// lldbr-check:(issue_22656::StructWithZeroSizedField) zs = StructWithZeroSizedField { x: ZeroSizedStruct { }, y: 123, z: ZeroSizedStruct { }, w: 456 }
+// lldbr-command:continue
#![allow(unused_variables)]
#![allow(dead_code)]
// FIRST ITERATION
// lldb-command:print x
-// lldb-check:[...]$0 = 1
+// lldbg-check:[...]$0 = 1
+// lldbr-check:(i32) x = 1
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(i32) x = -1
// lldb-command:continue
// SECOND ITERATION
// lldb-command:print x
-// lldb-check:[...]$2 = 2
+// lldbg-check:[...]$2 = 2
+// lldbr-check:(i32) x = 2
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$3 = -2
+// lldbg-check:[...]$3 = -2
+// lldbr-check:(i32) x = -2
// lldb-command:continue
// THIRD ITERATION
// lldb-command:print x
-// lldb-check:[...]$4 = 3
+// lldbg-check:[...]$4 = 3
+// lldbr-check:(i32) x = 3
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$5 = -3
+// lldbg-check:[...]$5 = -3
+// lldbr-check:(i32) x = -3
// lldb-command:continue
// AFTER LOOP
// lldb-command:print x
-// lldb-check:[...]$6 = 1000000
+// lldbg-check:[...]$6 = 1000000
+// lldbr-check:(i32) x = 1000000
// lldb-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// BEFORE if
// lldb-command:print x
-// lldb-check:[...]$0 = 999
+// lldbg-check:[...]$0 = 999
+// lldbr-check:(i32) x = 999
// lldb-command:print y
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(i32) y = -1
// lldb-command:continue
// AT BEGINNING of 'then' block
// lldb-command:print x
-// lldb-check:[...]$2 = 999
+// lldbg-check:[...]$2 = 999
+// lldbr-check:(i32) x = 999
// lldb-command:print y
-// lldb-check:[...]$3 = -1
+// lldbg-check:[...]$3 = -1
+// lldbr-check:(i32) y = -1
// lldb-command:continue
// AFTER 1st redeclaration of 'x'
// lldb-command:print x
-// lldb-check:[...]$4 = 1001
+// lldbg-check:[...]$4 = 1001
+// lldbr-check:(i32) x = 1001
// lldb-command:print y
-// lldb-check:[...]$5 = -1
+// lldbg-check:[...]$5 = -1
+// lldbr-check:(i32) y = -1
// lldb-command:continue
// AFTER 2st redeclaration of 'x'
// lldb-command:print x
-// lldb-check:[...]$6 = 1002
+// lldbg-check:[...]$6 = 1002
+// lldbr-check:(i32) x = 1002
// lldb-command:print y
-// lldb-check:[...]$7 = 1003
+// lldbg-check:[...]$7 = 1003
+// lldbr-check:(i32) y = 1003
// lldb-command:continue
// AFTER 1st if expression
// lldb-command:print x
-// lldb-check:[...]$8 = 999
+// lldbg-check:[...]$8 = 999
+// lldbr-check:(i32) x = 999
// lldb-command:print y
-// lldb-check:[...]$9 = -1
+// lldbg-check:[...]$9 = -1
+// lldbr-check:(i32) y = -1
// lldb-command:continue
// BEGINNING of else branch
// lldb-command:print x
-// lldb-check:[...]$10 = 999
+// lldbg-check:[...]$10 = 999
+// lldbr-check:(i32) x = 999
// lldb-command:print y
-// lldb-check:[...]$11 = -1
+// lldbg-check:[...]$11 = -1
+// lldbr-check:(i32) y = -1
// lldb-command:continue
// BEGINNING of else branch
// lldb-command:print x
-// lldb-check:[...]$12 = 1004
+// lldbg-check:[...]$12 = 1004
+// lldbr-check:(i32) x = 1004
// lldb-command:print y
-// lldb-check:[...]$13 = 1005
+// lldbg-check:[...]$13 = 1005
+// lldbr-check:(i32) y = 1005
// lldb-command:continue
// BEGINNING of else branch
// lldb-command:print x
-// lldb-check:[...]$14 = 999
+// lldbg-check:[...]$14 = 999
+// lldbr-check:(i32) x = 999
// lldb-command:print y
-// lldb-check:[...]$15 = -1
+// lldbg-check:[...]$15 = -1
+// lldbr-check:(i32) y = -1
// lldb-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print shadowed
-// lldb-check:[...]$0 = 231
+// lldbg-check:[...]$0 = 231
+// lldbr-check:(i32) shadowed = 231
// lldb-command:print not_shadowed
-// lldb-check:[...]$1 = 232
+// lldbg-check:[...]$1 = 232
+// lldbr-check:(i32) not_shadowed = 232
// lldb-command:continue
// lldb-command:print shadowed
-// lldb-check:[...]$2 = 233
+// lldbg-check:[...]$2 = 233
+// lldbr-check:(i32) shadowed = 233
// lldb-command:print not_shadowed
-// lldb-check:[...]$3 = 232
+// lldbg-check:[...]$3 = 232
+// lldbr-check:(i32) not_shadowed = 232
// lldb-command:print local_to_arm
-// lldb-check:[...]$4 = 234
+// lldbg-check:[...]$4 = 234
+// lldbr-check:(i32) local_to_arm = 234
// lldb-command:continue
// lldb-command:print shadowed
-// lldb-check:[...]$5 = 236
+// lldbg-check:[...]$5 = 236
+// lldbr-check:(i32) shadowed = 236
// lldb-command:print not_shadowed
-// lldb-check:[...]$6 = 232
+// lldbg-check:[...]$6 = 232
+// lldbr-check:(i32) not_shadowed = 232
// lldb-command:continue
// lldb-command:print shadowed
-// lldb-check:[...]$7 = 237
+// lldbg-check:[...]$7 = 237
+// lldbr-check:(isize) shadowed = 237
// lldb-command:print not_shadowed
-// lldb-check:[...]$8 = 232
+// lldbg-check:[...]$8 = 232
+// lldbr-check:(i32) not_shadowed = 232
// lldb-command:print local_to_arm
-// lldb-check:[...]$9 = 238
+// lldbg-check:[...]$9 = 238
+// lldbr-check:(isize) local_to_arm = 238
// lldb-command:continue
// lldb-command:print shadowed
-// lldb-check:[...]$10 = 239
+// lldbg-check:[...]$10 = 239
+// lldbr-check:(isize) shadowed = 239
// lldb-command:print not_shadowed
-// lldb-check:[...]$11 = 232
+// lldbg-check:[...]$11 = 232
+// lldbr-check:(i32) not_shadowed = 232
// lldb-command:continue
// lldb-command:print shadowed
-// lldb-check:[...]$12 = 241
+// lldbg-check:[...]$12 = 241
+// lldbr-check:(isize) shadowed = 241
// lldb-command:print not_shadowed
-// lldb-check:[...]$13 = 232
+// lldbg-check:[...]$13 = 232
+// lldbr-check:(i32) not_shadowed = 232
// lldb-command:continue
// lldb-command:print shadowed
-// lldb-check:[...]$14 = 243
+// lldbg-check:[...]$14 = 243
+// lldbr-check:(i32) shadowed = 243
// lldb-command:print *local_to_arm
-// lldb-check:[...]$15 = 244
+// lldbg-check:[...]$15 = 244
+// lldbr-check:(i32) *local_to_arm = 244
// lldb-command:continue
// lldb-command:print shadowed
-// lldb-check:[...]$16 = 231
+// lldbg-check:[...]$16 = 231
+// lldbr-check:(i32) shadowed = 231
// lldb-command:print not_shadowed
-// lldb-check:[...]$17 = 232
+// lldbg-check:[...]$17 = 232
+// lldbr-check:(i32) not_shadowed = 232
// lldb-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print x
-// lldb-check:[...]$0 = false
+// lldbg-check:[...]$0 = false
+// lldbr-check:(bool) x = false
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$1 = false
+// lldbg-check:[...]$1 = false
+// lldbr-check:(bool) x = false
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$2 = 1000
+// lldbg-check:[...]$2 = 1000
+// lldbr-check:(isize) x = 1000
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$3 = 2.5
+// lldbg-check:[...]$3 = 2.5
+// lldbr-check:(f64) x = 2.5
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$4 = true
+// lldbg-check:[...]$4 = true
+// lldbr-check:(bool) x = true
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$5 = false
+// lldbg-check:[...]$5 = false
+// lldbr-check:(bool) x = false
// lldb-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// FIRST ITERATION
// lldb-command:print x
-// lldb-check:[...]$0 = 0
+// lldbg-check:[...]$0 = 0
+// lldbr-check:(i32) x = 0
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$1 = 1
+// lldbg-check:[...]$1 = 1
+// lldbr-check:(i32) x = 1
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$2 = 101
+// lldbg-check:[...]$2 = 101
+// lldbr-check:(i32) x = 101
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$3 = 101
+// lldbg-check:[...]$3 = 101
+// lldbr-check:(i32) x = 101
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$4 = -987
+// lldbg-check:[...]$4 = -987
+// lldbr-check:(i32) x = -987
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$5 = 101
+// lldbg-check:[...]$5 = 101
+// lldbr-check:(i32) x = 101
// lldb-command:continue
// SECOND ITERATION
// lldb-command:print x
-// lldb-check:[...]$6 = 1
+// lldbg-check:[...]$6 = 1
+// lldbr-check:(i32) x = 1
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$7 = 2
+// lldbg-check:[...]$7 = 2
+// lldbr-check:(i32) x = 2
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$8 = 102
+// lldbg-check:[...]$8 = 102
+// lldbr-check:(i32) x = 102
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$9 = 102
+// lldbg-check:[...]$9 = 102
+// lldbr-check:(i32) x = 102
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$10 = -987
+// lldbg-check:[...]$10 = -987
+// lldbr-check:(i32) x = -987
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$11 = 102
+// lldbg-check:[...]$11 = 102
+// lldbr-check:(i32) x = 102
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$12 = 2
+// lldbg-check:[...]$12 = 2
+// lldbr-check:(i32) x = 2
// lldb-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print x
-// lldb-check:[...]$0 = false
+// lldbg-check:[...]$0 = false
+// lldbr-check:(bool) x = false
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$1 = false
+// lldbg-check:[...]$1 = false
+// lldbr-check:(bool) x = false
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$2 = 1000
+// lldbg-check:[...]$2 = 1000
+// lldbr-check:(isize) x = 1000
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$3 = 2.5
+// lldbg-check:[...]$3 = 2.5
+// lldbr-check:(f64) x = 2.5
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$4 = true
+// lldbg-check:[...]$4 = true
+// lldbr-check:(bool) x = true
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$5 = false
+// lldbg-check:[...]$5 = false
+// lldbr-check:(bool) x = false
// lldb-command:continue
// FIRST ITERATION
// lldb-command:print x
-// lldb-check:[...]$0 = 0
+// lldbg-check:[...]$0 = 0
+// lldbr-check:(i32) x = 0
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$1 = 1
+// lldbg-check:[...]$1 = 1
+// lldbr-check:(i32) x = 1
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$2 = 101
+// lldbg-check:[...]$2 = 101
+// lldbr-check:(i32) x = 101
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$3 = 101
+// lldbg-check:[...]$3 = 101
+// lldbr-check:(i32) x = 101
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$4 = -987
+// lldbg-check:[...]$4 = -987
+// lldbr-check:(i32) x = -987
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$5 = 101
+// lldbg-check:[...]$5 = 101
+// lldbr-check:(i32) x = 101
// lldb-command:continue
// SECOND ITERATION
// lldb-command:print x
-// lldb-check:[...]$6 = 1
+// lldbg-check:[...]$6 = 1
+// lldbr-check:(i32) x = 1
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$7 = 2
+// lldbg-check:[...]$7 = 2
+// lldbr-check:(i32) x = 2
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$8 = 102
+// lldbg-check:[...]$8 = 102
+// lldbr-check:(i32) x = 102
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$9 = 102
+// lldbg-check:[...]$9 = 102
+// lldbr-check:(i32) x = 102
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$10 = -987
+// lldbg-check:[...]$10 = -987
+// lldbr-check:(i32) x = -987
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$11 = 102
+// lldbg-check:[...]$11 = 102
+// lldbr-check:(i32) x = 102
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$12 = 2
+// lldbg-check:[...]$12 = 2
+// lldbr-check:(i32) x = 2
// lldb-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print a
-// lldb-check:[...]$0 = 10
+// lldbg-check:[...]$0 = 10
+// lldbr-check:(i32) a = 10
// lldb-command:print b
-// lldb-check:[...]$1 = 34
+// lldbg-check:[...]$1 = 34
+// lldbr-check:(i32) b = 34
// lldb-command:continue
// lldb-command:print a
-// lldb-check:[...]$2 = 890242
+// lldbg-check:[...]$2 = 890242
+// lldbr-check:(i32) a = 10
// lldb-command:print b
-// lldb-check:[...]$3 = 34
+// lldbg-check:[...]$3 = 34
+// lldbr-check:(i32) b = 34
// lldb-command:continue
// lldb-command:print a
-// lldb-check:[...]$4 = 10
+// lldbg-check:[...]$4 = 10
+// lldbr-check:(i32) a = 10
// lldb-command:print b
-// lldb-check:[...]$5 = 34
+// lldbg-check:[...]$5 = 34
+// lldbr-check:(i32) b = 34
// lldb-command:continue
// lldb-command:print a
-// lldb-check:[...]$6 = 102
+// lldbg-check:[...]$6 = 102
+// lldbr-check:(i32) a = 10
// lldb-command:print b
-// lldb-check:[...]$7 = 34
+// lldbg-check:[...]$7 = 34
+// lldbr-check:(i32) b = 34
// lldb-command:continue
-// lldb-command:print a
-// lldb-check:[...]$8 = 110
-// lldb-command:print b
-// lldb-check:[...]$9 = 34
-// lldb-command:continue
-
-// lldb-command:print a
-// lldb-check:[...]$10 = 10
-// lldb-command:print b
-// lldb-check:[...]$11 = 34
-// lldb-command:continue
-
-// lldb-command:print a
-// lldb-check:[...]$12 = 10
-// lldb-command:print b
-// lldb-check:[...]$13 = 34
-// lldb-command:print c
-// lldb-check:[...]$14 = 400
-// lldb-command:continue
+// Don't test this with rust-enabled lldb for now; see issue #48807
+// lldbg-command:print a
+// lldbg-check:[...]$8 = 110
+// lldbg-command:print b
+// lldbg-check:[...]$9 = 34
+// lldbg-command:continue
+
+// lldbg-command:print a
+// lldbg-check:[...]$10 = 10
+// lldbg-command:print b
+// lldbg-check:[...]$11 = 34
+// lldbg-command:continue
+
+// lldbg-command:print a
+// lldbg-check:[...]$12 = 10
+// lldbg-command:print b
+// lldbg-check:[...]$13 = 34
+// lldbg-command:print c
+// lldbg-check:[...]$14 = 400
+// lldbg-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// STRUCT EXPRESSION
// lldb-command:print val
-// lldb-check:[...]$0 = -1
+// lldbg-check:[...]$0 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$1 = 10
+// lldbg-check:[...]$1 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$2 = 11
+// lldbg-check:[...]$2 = 11
+// lldbr-check:(isize) val = 11
// lldb-command:print ten
-// lldb-check:[...]$3 = 10
+// lldbg-check:[...]$3 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$4 = -1
+// lldbg-check:[...]$4 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$5 = 10
+// lldbg-check:[...]$5 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// FUNCTION CALL
// lldb-command:print val
-// lldb-check:[...]$6 = -1
+// lldbg-check:[...]$6 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$7 = 10
+// lldbg-check:[...]$7 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$8 = 12
+// lldbg-check:[...]$8 = 12
+// lldbr-check:(isize) val = 12
// lldb-command:print ten
-// lldb-check:[...]$9 = 10
+// lldbg-check:[...]$9 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$10 = -1
+// lldbg-check:[...]$10 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$11 = 10
+// lldbg-check:[...]$11 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// TUPLE EXPRESSION
// lldb-command:print val
-// lldb-check:[...]$12 = -1
+// lldbg-check:[...]$12 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$13 = 10
+// lldbg-check:[...]$13 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$14 = 13
+// lldbg-check:[...]$14 = 13
+// lldbr-check:(isize) val = 13
// lldb-command:print ten
-// lldb-check:[...]$15 = 10
+// lldbg-check:[...]$15 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$16 = -1
+// lldbg-check:[...]$16 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$17 = 10
+// lldbg-check:[...]$17 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// VEC EXPRESSION
// lldb-command:print val
-// lldb-check:[...]$18 = -1
+// lldbg-check:[...]$18 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$19 = 10
+// lldbg-check:[...]$19 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$20 = 14
+// lldbg-check:[...]$20 = 14
+// lldbr-check:(isize) val = 14
// lldb-command:print ten
-// lldb-check:[...]$21 = 10
+// lldbg-check:[...]$21 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$22 = -1
+// lldbg-check:[...]$22 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$23 = 10
+// lldbg-check:[...]$23 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// REPEAT VEC EXPRESSION
// lldb-command:print val
-// lldb-check:[...]$24 = -1
+// lldbg-check:[...]$24 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$25 = 10
+// lldbg-check:[...]$25 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$26 = 15
+// lldbg-check:[...]$26 = 15
+// lldbr-check:(isize) val = 15
// lldb-command:print ten
-// lldb-check:[...]$27 = 10
+// lldbg-check:[...]$27 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$28 = -1
+// lldbg-check:[...]$28 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$29 = 10
+// lldbg-check:[...]$29 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// ASSIGNMENT EXPRESSION
// lldb-command:print val
-// lldb-check:[...]$30 = -1
+// lldbg-check:[...]$30 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$31 = 10
+// lldbg-check:[...]$31 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$32 = 16
+// lldbg-check:[...]$32 = 16
+// lldbr-check:(isize) val = 16
// lldb-command:print ten
-// lldb-check:[...]$33 = 10
+// lldbg-check:[...]$33 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$34 = -1
+// lldbg-check:[...]$34 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$35 = 10
+// lldbg-check:[...]$35 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// ARITHMETIC EXPRESSION
// lldb-command:print val
-// lldb-check:[...]$36 = -1
+// lldbg-check:[...]$36 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$37 = 10
+// lldbg-check:[...]$37 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$38 = 17
+// lldbg-check:[...]$38 = 17
+// lldbr-check:(isize) val = 17
// lldb-command:print ten
-// lldb-check:[...]$39 = 10
+// lldbg-check:[...]$39 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$40 = -1
+// lldbg-check:[...]$40 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$41 = 10
+// lldbg-check:[...]$41 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// INDEX EXPRESSION
// lldb-command:print val
-// lldb-check:[...]$42 = -1
+// lldbg-check:[...]$42 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$43 = 10
+// lldbg-check:[...]$43 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$44 = 18
+// lldbg-check:[...]$44 = 18
+// lldbr-check:(isize) val = 18
// lldb-command:print ten
-// lldb-check:[...]$45 = 10
+// lldbg-check:[...]$45 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
// lldb-command:print val
-// lldb-check:[...]$46 = -1
+// lldbg-check:[...]$46 = -1
+// lldbr-check:(i32) val = -1
// lldb-command:print ten
-// lldb-check:[...]$47 = 10
+// lldbg-check:[...]$47 = 10
+// lldbr-check:(isize) ten = 10
// lldb-command:continue
#![allow(unused_variables)]
// STACK BY REF
// lldb-command:print *self
-// lldb-check:[...]$0 = Struct<(u32, i32)> { x: (8888, -8888) }
+// lldbg-check:[...]$0 = Struct<(u32, i32)> { x: (8888, -8888) }
+// lldbr-check:(method_on_generic_struct::Struct<(u32, i32)>) *self = { x = { = 8888 = -8888 } }
// lldb-command:print arg1
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(isize) arg1 = -1
// lldb-command:print arg2
-// lldb-check:[...]$2 = -2
+// lldbg-check:[...]$2 = -2
+// lldbr-check:(isize) arg2 = -2
// lldb-command:continue
// STACK BY VAL
// lldb-command:print self
-// lldb-check:[...]$3 = Struct<(u32, i32)> { x: (8888, -8888) }
+// lldbg-check:[...]$3 = Struct<(u32, i32)> { x: (8888, -8888) }
+// lldbr-check:(method_on_generic_struct::Struct<(u32, i32)>) self = { x = { = 8888 = -8888 } }
// lldb-command:print arg1
-// lldb-check:[...]$4 = -3
+// lldbg-check:[...]$4 = -3
+// lldbr-check:(isize) arg1 = -3
// lldb-command:print arg2
-// lldb-check:[...]$5 = -4
+// lldbg-check:[...]$5 = -4
+// lldbr-check:(isize) arg2 = -4
// lldb-command:continue
// OWNED BY REF
// lldb-command:print *self
-// lldb-check:[...]$6 = Struct<f64> { x: 1234.5 }
+// lldbg-check:[...]$6 = Struct<f64> { x: 1234.5 }
+// lldbr-check:(method_on_generic_struct::Struct<f64>) *self = Struct<f64> { x: 1234.5 }
// lldb-command:print arg1
-// lldb-check:[...]$7 = -5
+// lldbg-check:[...]$7 = -5
+// lldbr-check:(isize) arg1 = -5
// lldb-command:print arg2
-// lldb-check:[...]$8 = -6
+// lldbg-check:[...]$8 = -6
+// lldbr-check:(isize) arg2 = -6
// lldb-command:continue
// OWNED BY VAL
// lldb-command:print self
-// lldb-check:[...]$9 = Struct<f64> { x: 1234.5 }
+// lldbg-check:[...]$9 = Struct<f64> { x: 1234.5 }
+// lldbr-check:(method_on_generic_struct::Struct<f64>) self = Struct<f64> { x: 1234.5 }
// lldb-command:print arg1
-// lldb-check:[...]$10 = -7
+// lldbg-check:[...]$10 = -7
+// lldbr-check:(isize) arg1 = -7
// lldb-command:print arg2
-// lldb-check:[...]$11 = -8
+// lldbg-check:[...]$11 = -8
+// lldbr-check:(isize) arg2 = -8
// lldb-command:continue
// OWNED MOVED
// lldb-command:print *self
-// lldb-check:[...]$12 = Struct<f64> { x: 1234.5 }
+// lldbg-check:[...]$12 = Struct<f64> { x: 1234.5 }
+// lldbr-check:(method_on_generic_struct::Struct<f64>) *self = Struct<f64> { x: 1234.5 }
// lldb-command:print arg1
-// lldb-check:[...]$13 = -9
+// lldbg-check:[...]$13 = -9
+// lldbr-check:(isize) arg1 = -9
// lldb-command:print arg2
-// lldb-check:[...]$14 = -10
+// lldbg-check:[...]$14 = -10
+// lldbr-check:(isize) arg2 = -10
// lldb-command:continue
// STACK BY REF
// lldb-command:print *self
-// lldb-check:[...]$0 = Struct { x: 100 }
+// lldbg-check:[...]$0 = Struct { x: 100 }
+// lldbr-check:(method_on_struct::Struct) *self = Struct { x: 100 }
// lldb-command:print arg1
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(isize) arg1 = -1
// lldb-command:print arg2
-// lldb-check:[...]$2 = -2
+// lldbg-check:[...]$2 = -2
+// lldbr-check:(isize) arg2 = -2
// lldb-command:continue
// STACK BY VAL
// lldb-command:print self
-// lldb-check:[...]$3 = Struct { x: 100 }
+// lldbg-check:[...]$3 = Struct { x: 100 }
+// lldbr-check:(method_on_struct::Struct) self = Struct { x: 100 }
// lldb-command:print arg1
-// lldb-check:[...]$4 = -3
+// lldbg-check:[...]$4 = -3
+// lldbr-check:(isize) arg1 = -3
// lldb-command:print arg2
-// lldb-check:[...]$5 = -4
+// lldbg-check:[...]$5 = -4
+// lldbr-check:(isize) arg2 = -4
// lldb-command:continue
// OWNED BY REF
// lldb-command:print *self
-// lldb-check:[...]$6 = Struct { x: 200 }
+// lldbg-check:[...]$6 = Struct { x: 200 }
+// lldbr-check:(method_on_struct::Struct) *self = Struct { x: 200 }
// lldb-command:print arg1
-// lldb-check:[...]$7 = -5
+// lldbg-check:[...]$7 = -5
+// lldbr-check:(isize) arg1 = -5
// lldb-command:print arg2
-// lldb-check:[...]$8 = -6
+// lldbg-check:[...]$8 = -6
+// lldbr-check:(isize) arg2 = -6
// lldb-command:continue
// OWNED BY VAL
// lldb-command:print self
-// lldb-check:[...]$9 = Struct { x: 200 }
+// lldbg-check:[...]$9 = Struct { x: 200 }
+// lldbr-check:(method_on_struct::Struct) self = Struct { x: 200 }
// lldb-command:print arg1
-// lldb-check:[...]$10 = -7
+// lldbg-check:[...]$10 = -7
+// lldbr-check:(isize) arg1 = -7
// lldb-command:print arg2
-// lldb-check:[...]$11 = -8
+// lldbg-check:[...]$11 = -8
+// lldbr-check:(isize) arg2 = -8
// lldb-command:continue
// OWNED MOVED
// lldb-command:print *self
-// lldb-check:[...]$12 = Struct { x: 200 }
+// lldbg-check:[...]$12 = Struct { x: 200 }
+// lldbr-check:(method_on_struct::Struct) *self = Struct { x: 200 }
// lldb-command:print arg1
-// lldb-check:[...]$13 = -9
+// lldbg-check:[...]$13 = -9
+// lldbr-check:(isize) arg1 = -9
// lldb-command:print arg2
-// lldb-check:[...]$14 = -10
+// lldbg-check:[...]$14 = -10
+// lldbr-check:(isize) arg2 = -10
// lldb-command:continue
// STACK BY REF
// lldb-command:print *self
-// lldb-check:[...]$0 = Struct { x: 100 }
+// lldbg-check:[...]$0 = Struct { x: 100 }
+// lldbr-check:(method_on_trait::Struct) *self = Struct { x: 100 }
// lldb-command:print arg1
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(isize) arg1 = -1
// lldb-command:print arg2
-// lldb-check:[...]$2 = -2
+// lldbg-check:[...]$2 = -2
+// lldbr-check:(isize) arg2 = -2
// lldb-command:continue
// STACK BY VAL
// lldb-command:print self
-// lldb-check:[...]$3 = Struct { x: 100 }
+// lldbg-check:[...]$3 = Struct { x: 100 }
+// lldbr-check:(method_on_trait::Struct) self = Struct { x: 100 }
// lldb-command:print arg1
-// lldb-check:[...]$4 = -3
+// lldbg-check:[...]$4 = -3
+// lldbr-check:(isize) arg1 = -3
// lldb-command:print arg2
-// lldb-check:[...]$5 = -4
+// lldbg-check:[...]$5 = -4
+// lldbr-check:(isize) arg2 = -4
// lldb-command:continue
// OWNED BY REF
// lldb-command:print *self
-// lldb-check:[...]$6 = Struct { x: 200 }
+// lldbg-check:[...]$6 = Struct { x: 200 }
+// lldbr-check:(method_on_trait::Struct) *self = Struct { x: 200 }
// lldb-command:print arg1
-// lldb-check:[...]$7 = -5
+// lldbg-check:[...]$7 = -5
+// lldbr-check:(isize) arg1 = -5
// lldb-command:print arg2
-// lldb-check:[...]$8 = -6
+// lldbg-check:[...]$8 = -6
+// lldbr-check:(isize) arg2 = -6
// lldb-command:continue
// OWNED BY VAL
// lldb-command:print self
-// lldb-check:[...]$9 = Struct { x: 200 }
+// lldbg-check:[...]$9 = Struct { x: 200 }
+// lldbr-check:(method_on_trait::Struct) self = Struct { x: 200 }
// lldb-command:print arg1
-// lldb-check:[...]$10 = -7
+// lldbg-check:[...]$10 = -7
+// lldbr-check:(isize) arg1 = -7
// lldb-command:print arg2
-// lldb-check:[...]$11 = -8
+// lldbg-check:[...]$11 = -8
+// lldbr-check:(isize) arg2 = -8
// lldb-command:continue
// OWNED MOVED
// lldb-command:print *self
-// lldb-check:[...]$12 = Struct { x: 200 }
+// lldbg-check:[...]$12 = Struct { x: 200 }
+// lldbr-check:(method_on_trait::Struct) *self = Struct { x: 200 }
// lldb-command:print arg1
-// lldb-check:[...]$13 = -9
+// lldbg-check:[...]$13 = -9
+// lldbr-check:(isize) arg1 = -9
// lldb-command:print arg2
-// lldb-check:[...]$14 = -10
+// lldbg-check:[...]$14 = -10
+// lldbr-check:(isize) arg2 = -10
// lldb-command:continue
// STACK BY REF
// lldb-command:print *self
-// lldb-check:[...]$0 = TupleStruct(100, -100.5)
+// lldbg-check:[...]$0 = TupleStruct(100, -100.5)
+// lldbr-check:(method_on_tuple_struct::TupleStruct) *self = { = 100 = -100.5 }
// lldb-command:print arg1
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(isize) arg1 = -1
// lldb-command:print arg2
-// lldb-check:[...]$2 = -2
+// lldbg-check:[...]$2 = -2
+// lldbr-check:(isize) arg2 = -2
// lldb-command:continue
// STACK BY VAL
// lldb-command:print self
-// lldb-check:[...]$3 = TupleStruct(100, -100.5)
+// lldbg-check:[...]$3 = TupleStruct(100, -100.5)
+// lldbr-check:(method_on_tuple_struct::TupleStruct) self = { = 100 = -100.5 }
// lldb-command:print arg1
-// lldb-check:[...]$4 = -3
+// lldbg-check:[...]$4 = -3
+// lldbr-check:(isize) arg1 = -3
// lldb-command:print arg2
-// lldb-check:[...]$5 = -4
+// lldbg-check:[...]$5 = -4
+// lldbr-check:(isize) arg2 = -4
// lldb-command:continue
// OWNED BY REF
// lldb-command:print *self
-// lldb-check:[...]$6 = TupleStruct(200, -200.5)
+// lldbg-check:[...]$6 = TupleStruct(200, -200.5)
+// lldbr-check:(method_on_tuple_struct::TupleStruct) *self = { = 200 = -200.5 }
// lldb-command:print arg1
-// lldb-check:[...]$7 = -5
+// lldbg-check:[...]$7 = -5
+// lldbr-check:(isize) arg1 = -5
// lldb-command:print arg2
-// lldb-check:[...]$8 = -6
+// lldbg-check:[...]$8 = -6
+// lldbr-check:(isize) arg2 = -6
// lldb-command:continue
// OWNED BY VAL
// lldb-command:print self
-// lldb-check:[...]$9 = TupleStruct(200, -200.5)
+// lldbg-check:[...]$9 = TupleStruct(200, -200.5)
+// lldbr-check:(method_on_tuple_struct::TupleStruct) self = { = 200 = -200.5 }
// lldb-command:print arg1
-// lldb-check:[...]$10 = -7
+// lldbg-check:[...]$10 = -7
+// lldbr-check:(isize) arg1 = -7
// lldb-command:print arg2
-// lldb-check:[...]$11 = -8
+// lldbg-check:[...]$11 = -8
+// lldbr-check:(isize) arg2 = -8
// lldb-command:continue
// OWNED MOVED
// lldb-command:print *self
-// lldb-check:[...]$12 = TupleStruct(200, -200.5)
+// lldbg-check:[...]$12 = TupleStruct(200, -200.5)
+// lldbr-check:(method_on_tuple_struct::TupleStruct) *self = { = 200 = -200.5 }
// lldb-command:print arg1
-// lldb-check:[...]$13 = -9
+// lldbg-check:[...]$13 = -9
+// lldbr-check:(isize) arg1 = -9
// lldb-command:print arg2
-// lldb-check:[...]$14 = -10
+// lldbg-check:[...]$14 = -10
+// lldbr-check:(isize) arg2 = -10
// lldb-command:continue
// lldb-command:run
// lldb-command:print xxx
-// lldb-check:[...]$0 = 12345
+// lldbg-check:[...]$0 = 12345
+// lldbr-check:(u32) xxx = 12345
// lldb-command:continue
// lldb-command:print yyy
-// lldb-check:[...]$1 = 67890
+// lldbg-check:[...]$1 = 67890
+// lldbr-check:(u64) yyy = 67890
// lldb-command:continue
// lldb-command:run
// lldb-command:print abc
-// lldb-check:[...]$0 = 10101
+// lldbg-check:[...]$0 = 10101
+// lldbr-check:(i32) abc = 10101
// lldb-command:continue
// lldb-command:print abc
-// lldb-check:[...]$1 = 20202
+// lldbg-check:[...]$1 = 20202
+// lldbr-check:(i32) abc = 20202
// lldb-command:continue
// lldb-command:print abc
-// lldb-check:[...]$2 = 30303
+// lldbg-check:[...]$2 = 30303
+// lldbr-check:(i32) abc = 30303
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print a
-// lldb-check:[...]$0 = 10101
+// lldbg-check:[...]$0 = 10101
+// lldbr-check:(i32) a = 10101
// lldb-command:continue
// lldb-command:print b
-// lldb-check:[...]$1 = 20202
+// lldbg-check:[...]$1 = 20202
+// lldbr-check:(i32) b = 20202
// lldb-command:continue
// lldb-command:print c
-// lldb-check:[...]$2 = 30303
+// lldbg-check:[...]$2 = 30303
+// lldbr-check:(i32) c = 30303
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print x
-// lldb-check:[...]$0 = false
+// lldbg-check:[...]$0 = false
+// lldbr-check:(bool) x = false
// lldb-command:print y
-// lldb-check:[...]$1 = true
+// lldbg-check:[...]$1 = true
+// lldbr-check:(bool) y = true
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$2 = 10
+// lldbg-check:[...]$2 = 10
+// lldbr-check:(i32) x = 10
// lldb-command:print y
-// lldb-check:[...]$3 = true
+// lldbg-check:[...]$3 = true
+// lldbr-check:(bool) y = true
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$4 = 10.5
+// lldbg-check:[...]$4 = 10.5
+// lldbr-check:(f64) x = 10.5
// lldb-command:print y
-// lldb-check:[...]$5 = 20
+// lldbg-check:[...]$5 = 20
+// lldbr-check:(i32) y = 20
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$6 = true
+// lldbg-check:[...]$6 = true
+// lldbr-check:(bool) x = true
// lldb-command:print y
-// lldb-check:[...]$7 = 2220
+// lldbg-check:[...]$7 = 2220
+// lldbr-check:(i32) y = 2220
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$8 = 203203.5
+// lldbg-check:[...]$8 = 203203.5
+// lldbr-check:(f64) x = 203203.5
// lldb-command:print y
-// lldb-check:[...]$9 = 2220
+// lldbg-check:[...]$9 = 2220
+// lldbr-check:(i32) y = 2220
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$10 = 10.5
+// lldbg-check:[...]$10 = 10.5
+// lldbr-check:(f64) x = 10.5
// lldb-command:print y
-// lldb-check:[...]$11 = 20
+// lldbg-check:[...]$11 = 20
+// lldbr-check:(i32) y = 20
// lldb-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print packed
-// lldb-check:[...]$0 = Packed { x: 123, y: 234, z: 345 }
+// lldbg-check:[...]$0 = Packed { x: 123, y: 234, z: 345 }
+// lldbr-check:(packed_struct_with_destructor::Packed) packed = Packed { x: 123, y: 234, z: 345 }
// lldb-command:print packedInPacked
-// lldb-check:[...]$1 = PackedInPacked { a: 1111, b: Packed { x: 2222, y: 3333, z: 4444 }, c: 5555, d: Packed { x: 6666, y: 7777, z: 8888 } }
+// lldbg-check:[...]$1 = PackedInPacked { a: 1111, b: Packed { x: 2222, y: 3333, z: 4444 }, c: 5555, d: Packed { x: 6666, y: 7777, z: 8888 } }
+// lldbr-check:(packed_struct_with_destructor::PackedInPacked) packedInPacked = PackedInPacked { a: 1111, b: Packed { x: 2222, y: 3333, z: 4444 }, c: 5555, d: Packed { x: 6666, y: 7777, z: 8888 } }
// lldb-command:print packedInUnpacked
-// lldb-check:[...]$2 = PackedInUnpacked { a: -1111, b: Packed { x: -2222, y: -3333, z: -4444 }, c: -5555, d: Packed { x: -6666, y: -7777, z: -8888 } }
+// lldbg-check:[...]$2 = PackedInUnpacked { a: -1111, b: Packed { x: -2222, y: -3333, z: -4444 }, c: -5555, d: Packed { x: -6666, y: -7777, z: -8888 } }
+// lldbr-check:(packed_struct_with_destructor::PackedInUnpacked) packedInUnpacked = PackedInUnpacked { a: -1111, b: Packed { x: -2222, y: -3333, z: -4444 }, c: -5555, d: Packed { x: -6666, y: -7777, z: -8888 } }
// lldb-command:print unpackedInPacked
-// lldb-check:[...]$3 = UnpackedInPacked { a: 987, b: Unpacked { x: 876, y: 765, z: 654 }, c: Unpacked { x: 543, y: 432, z: 321 }, d: 210 }
+// lldbg-check:[...]$3 = UnpackedInPacked { a: 987, b: Unpacked { x: 876, y: 765, z: 654 }, c: Unpacked { x: 543, y: 432, z: 321 }, d: 210 }
+// lldbr-check:(packed_struct_with_destructor::UnpackedInPacked) unpackedInPacked = UnpackedInPacked { a: 987, b: Unpacked { x: 876, y: 765, z: 654 }, c: Unpacked { x: 543, y: 432, z: 321 }, d: 210 }
// lldb-command:print packedInPackedWithDrop
-// lldb-check:[...]$4 = PackedInPackedWithDrop { a: 11, b: Packed { x: 22, y: 33, z: 44 }, c: 55, d: Packed { x: 66, y: 77, z: 88 } }
+// lldbg-check:[...]$4 = PackedInPackedWithDrop { a: 11, b: Packed { x: 22, y: 33, z: 44 }, c: 55, d: Packed { x: 66, y: 77, z: 88 } }
+// lldbr-check:(packed_struct_with_destructor::PackedInPackedWithDrop) packedInPackedWithDrop = PackedInPackedWithDrop { a: 11, b: Packed { x: 22, y: 33, z: 44 }, c: 55, d: Packed { x: 66, y: 77, z: 88 } }
// lldb-command:print packedInUnpackedWithDrop
-// lldb-check:[...]$5 = PackedInUnpackedWithDrop { a: -11, b: Packed { x: -22, y: -33, z: -44 }, c: -55, d: Packed { x: -66, y: -77, z: -88 } }
+// lldbg-check:[...]$5 = PackedInUnpackedWithDrop { a: -11, b: Packed { x: -22, y: -33, z: -44 }, c: -55, d: Packed { x: -66, y: -77, z: -88 } }
+// lldbr-check:(packed_struct_with_destructor::PackedInUnpackedWithDrop) packedInUnpackedWithDrop = PackedInUnpackedWithDrop { a: -11, b: Packed { x: -22, y: -33, z: -44 }, c: -55, d: Packed { x: -66, y: -77, z: -88 } }
// lldb-command:print unpackedInPackedWithDrop
-// lldb-check:[...]$6 = UnpackedInPackedWithDrop { a: 98, b: Unpacked { x: 87, y: 76, z: 65 }, c: Unpacked { x: 54, y: 43, z: 32 }, d: 21 }
+// lldbg-check:[...]$6 = UnpackedInPackedWithDrop { a: 98, b: Unpacked { x: 87, y: 76, z: 65 }, c: Unpacked { x: 54, y: 43, z: 32 }, d: 21 }
+// lldbr-check:(packed_struct_with_destructor::UnpackedInPackedWithDrop) unpackedInPackedWithDrop = UnpackedInPackedWithDrop { a: 98, b: Unpacked { x: 87, y: 76, z: 65 }, c: Unpacked { x: 54, y: 43, z: 32 }, d: 21 }
// lldb-command:print deeplyNested
-// lldb-check:[...]$7 = DeeplyNested { a: PackedInPacked { a: 1, b: Packed { x: 2, y: 3, z: 4 }, c: 5, d: Packed { x: 6, y: 7, z: 8 } }, b: UnpackedInPackedWithDrop { a: 9, b: Unpacked { x: 10, y: 11, z: 12 }, c: Unpacked { x: 13, y: 14, z: 15 }, d: 16 }, c: PackedInUnpacked { a: 17, b: Packed { x: 18, y: 19, z: 20 }, c: 21, d: Packed { x: 22, y: 23, z: 24 } }, d: PackedInUnpackedWithDrop { a: 25, b: Packed { x: 26, y: 27, z: 28 }, c: 29, d: Packed { x: 30, y: 31, z: 32 } }, e: UnpackedInPacked { a: 33, b: Unpacked { x: 34, y: 35, z: 36 }, c: Unpacked { x: 37, y: 38, z: 39 }, d: 40 }, f: PackedInPackedWithDrop { a: 41, b: Packed { x: 42, y: 43, z: 44 }, c: 45, d: Packed { x: 46, y: 47, z: 48 } } }
+// lldbg-check:[...]$7 = DeeplyNested { a: PackedInPacked { a: 1, b: Packed { x: 2, y: 3, z: 4 }, c: 5, d: Packed { x: 6, y: 7, z: 8 } }, b: UnpackedInPackedWithDrop { a: 9, b: Unpacked { x: 10, y: 11, z: 12 }, c: Unpacked { x: 13, y: 14, z: 15 }, d: 16 }, c: PackedInUnpacked { a: 17, b: Packed { x: 18, y: 19, z: 20 }, c: 21, d: Packed { x: 22, y: 23, z: 24 } }, d: PackedInUnpackedWithDrop { a: 25, b: Packed { x: 26, y: 27, z: 28 }, c: 29, d: Packed { x: 30, y: 31, z: 32 } }, e: UnpackedInPacked { a: 33, b: Unpacked { x: 34, y: 35, z: 36 }, c: Unpacked { x: 37, y: 38, z: 39 }, d: 40 }, f: PackedInPackedWithDrop { a: 41, b: Packed { x: 42, y: 43, z: 44 }, c: 45, d: Packed { x: 46, y: 47, z: 48 } } }
+// lldbr-check:(packed_struct_with_destructor::DeeplyNested) deeplyNested = DeeplyNested { a: PackedInPacked { a: 1, b: Packed { x: 2, y: 3, z: 4 }, c: 5, d: Packed { x: 6, y: 7, z: 8 } }, b: UnpackedInPackedWithDrop { a: 9, b: Unpacked { x: 10, y: 11, z: 12 }, c: Unpacked { x: 13, y: 14, z: 15 }, d: 16 }, c: PackedInUnpacked { a: 17, b: Packed { x: 18, y: 19, z: 20 }, c: 21, d: Packed { x: 22, y: 23, z: 24 } }, d: PackedInUnpackedWithDrop { a: 25, b: Packed { x: 26, y: 27, z: 28 }, c: 29, d: Packed { x: 30, y: 31, z: 32 } }, e: UnpackedInPacked { a: 33, b: Unpacked { x: 34, y: 35, z: 36 }, c: Unpacked { x: 37, y: 38, z: 39 }, d: 40 }, f: PackedInPackedWithDrop { a: 41, b: Packed { x: 42, y: 43, z: 44 }, c: 45, d: Packed { x: 46, y: 47, z: 48 } } }
#![allow(unused_variables)]
// lldb-command:run
// lldb-command:print packed
-// lldb-check:[...]$0 = Packed { x: 123, y: 234, z: 345 }
+// lldbg-check:[...]$0 = Packed { x: 123, y: 234, z: 345 }
+// lldbr-check:(packed_struct::Packed) packed = Packed { x: 123, y: 234, z: 345 }
// lldb-command:print packedInPacked
-// lldb-check:[...]$1 = PackedInPacked { a: 1111, b: Packed { x: 2222, y: 3333, z: 4444 }, c: 5555, d: Packed { x: 6666, y: 7777, z: 8888 } }
+// lldbg-check:[...]$1 = PackedInPacked { a: 1111, b: Packed { x: 2222, y: 3333, z: 4444 }, c: 5555, d: Packed { x: 6666, y: 7777, z: 8888 } }
+// lldbr-check:(packed_struct::PackedInPacked) packedInPacked = PackedInPacked { a: 1111, b: Packed { x: 2222, y: 3333, z: 4444 }, c: 5555, d: Packed { x: 6666, y: 7777, z: 8888 } }
// lldb-command:print packedInUnpacked
-// lldb-check:[...]$2 = PackedInUnpacked { a: -1111, b: Packed { x: -2222, y: -3333, z: -4444 }, c: -5555, d: Packed { x: -6666, y: -7777, z: -8888 } }
+// lldbg-check:[...]$2 = PackedInUnpacked { a: -1111, b: Packed { x: -2222, y: -3333, z: -4444 }, c: -5555, d: Packed { x: -6666, y: -7777, z: -8888 } }
+// lldbr-check:(packed_struct::PackedInUnpacked) packedInUnpacked = PackedInUnpacked { a: -1111, b: Packed { x: -2222, y: -3333, z: -4444 }, c: -5555, d: Packed { x: -6666, y: -7777, z: -8888 } }
// lldb-command:print unpackedInPacked
-// lldb-check:[...]$3 = UnpackedInPacked { a: 987, b: Unpacked { x: 876, y: 765, z: 654, w: 543 }, c: Unpacked { x: 432, y: 321, z: 210, w: 109 }, d: -98 }
+// lldbg-check:[...]$3 = UnpackedInPacked { a: 987, b: Unpacked { x: 876, y: 765, z: 654, w: 543 }, c: Unpacked { x: 432, y: 321, z: 210, w: 109 }, d: -98 }
+// lldbr-check:(packed_struct::UnpackedInPacked) unpackedInPacked = UnpackedInPacked { a: 987, b: Unpacked { x: 876, y: 765, z: 654, w: 543 }, c: Unpacked { x: 432, y: 321, z: 210, w: 109 }, d: -98 }
// lldb-command:print sizeof(packed)
-// lldb-check:[...]$4 = 14
+// lldbg-check:[...]$4 = 14
+// lldbr-check:(usize) = 14
// lldb-command:print sizeof(packedInPacked)
-// lldb-check:[...]$5 = 40
+// lldbg-check:[...]$5 = 40
+// lldbr-check:(usize) = 40
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// STACK BY REF
// lldb-command:print *self
-// lldb-check:[...]$0 = Struct { x: 100 }
+// lldbg-check:[...]$0 = Struct { x: 100 }
+// lldbr-check:(self_in_default_method::Struct) *self = Struct { x: 100 }
// lldb-command:print arg1
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(isize) arg1 = -1
// lldb-command:print arg2
-// lldb-check:[...]$2 = -2
+// lldbg-check:[...]$2 = -2
+// lldbr-check:(isize) arg2 = -2
// lldb-command:continue
// STACK BY VAL
// lldb-command:print self
-// lldb-check:[...]$3 = Struct { x: 100 }
+// lldbg-check:[...]$3 = Struct { x: 100 }
+// lldbr-check:(self_in_default_method::Struct) self = Struct { x: 100 }
// lldb-command:print arg1
-// lldb-check:[...]$4 = -3
+// lldbg-check:[...]$4 = -3
+// lldbr-check:(isize) arg1 = -3
// lldb-command:print arg2
-// lldb-check:[...]$5 = -4
+// lldbg-check:[...]$5 = -4
+// lldbr-check:(isize) arg2 = -4
// lldb-command:continue
// OWNED BY REF
// lldb-command:print *self
-// lldb-check:[...]$6 = Struct { x: 200 }
+// lldbg-check:[...]$6 = Struct { x: 200 }
+// lldbr-check:(self_in_default_method::Struct) *self = Struct { x: 200 }
// lldb-command:print arg1
-// lldb-check:[...]$7 = -5
+// lldbg-check:[...]$7 = -5
+// lldbr-check:(isize) arg1 = -5
// lldb-command:print arg2
-// lldb-check:[...]$8 = -6
+// lldbg-check:[...]$8 = -6
+// lldbr-check:(isize) arg2 = -6
// lldb-command:continue
// OWNED BY VAL
// lldb-command:print self
-// lldb-check:[...]$9 = Struct { x: 200 }
+// lldbg-check:[...]$9 = Struct { x: 200 }
+// lldbr-check:(self_in_default_method::Struct) self = Struct { x: 200 }
// lldb-command:print arg1
-// lldb-check:[...]$10 = -7
+// lldbg-check:[...]$10 = -7
+// lldbr-check:(isize) arg1 = -7
// lldb-command:print arg2
-// lldb-check:[...]$11 = -8
+// lldbg-check:[...]$11 = -8
+// lldbr-check:(isize) arg2 = -8
// lldb-command:continue
// OWNED MOVED
// lldb-command:print *self
-// lldb-check:[...]$12 = Struct { x: 200 }
+// lldbg-check:[...]$12 = Struct { x: 200 }
+// lldbr-check:(self_in_default_method::Struct) *self = Struct { x: 200 }
// lldb-command:print arg1
-// lldb-check:[...]$13 = -9
+// lldbg-check:[...]$13 = -9
+// lldbr-check:(isize) arg1 = -9
// lldb-command:print arg2
-// lldb-check:[...]$14 = -10
+// lldbg-check:[...]$14 = -10
+// lldbr-check:(isize) arg2 = -10
// lldb-command:continue
#![feature(box_syntax)]
// STACK BY REF
// lldb-command:print *self
-// lldb-check:[...]$0 = Struct { x: 987 }
+// lldbg-check:[...]$0 = Struct { x: 987 }
+// lldbr-check:(self_in_generic_default_method::Struct) *self = Struct { x: 987 }
// lldb-command:print arg1
-// lldb-check:[...]$1 = -1
+// lldbg-check:[...]$1 = -1
+// lldbr-check:(isize) arg1 = -1
// lldb-command:print arg2
-// lldb-check:[...]$2 = 2
+// lldbg-check:[...]$2 = 2
+// lldbr-check:(u16) arg2 = 2
// lldb-command:continue
// STACK BY VAL
// lldb-command:print self
-// lldb-check:[...]$3 = Struct { x: 987 }
+// lldbg-check:[...]$3 = Struct { x: 987 }
+// lldbr-check:(self_in_generic_default_method::Struct) self = Struct { x: 987 }
// lldb-command:print arg1
-// lldb-check:[...]$4 = -3
+// lldbg-check:[...]$4 = -3
+// lldbr-check:(isize) arg1 = -3
// lldb-command:print arg2
-// lldb-check:[...]$5 = -4
+// lldbg-check:[...]$5 = -4
+// lldbr-check:(i16) arg2 = -4
// lldb-command:continue
// OWNED BY REF
// lldb-command:print *self
-// lldb-check:[...]$6 = Struct { x: 879 }
+// lldbg-check:[...]$6 = Struct { x: 879 }
+// lldbr-check:(self_in_generic_default_method::Struct) *self = Struct { x: 879 }
// lldb-command:print arg1
-// lldb-check:[...]$7 = -5
+// lldbg-check:[...]$7 = -5
+// lldbr-check:(isize) arg1 = -5
// lldb-command:print arg2
-// lldb-check:[...]$8 = -6
+// lldbg-check:[...]$8 = -6
+// lldbr-check:(i32) arg2 = -6
// lldb-command:continue
// OWNED BY VAL
// lldb-command:print self
-// lldb-check:[...]$9 = Struct { x: 879 }
+// lldbg-check:[...]$9 = Struct { x: 879 }
+// lldbr-check:(self_in_generic_default_method::Struct) self = Struct { x: 879 }
// lldb-command:print arg1
-// lldb-check:[...]$10 = -7
+// lldbg-check:[...]$10 = -7
+// lldbr-check:(isize) arg1 = -7
// lldb-command:print arg2
-// lldb-check:[...]$11 = -8
+// lldbg-check:[...]$11 = -8
+// lldbr-check:(i64) arg2 = -8
// lldb-command:continue
// OWNED MOVED
// lldb-command:print *self
-// lldb-check:[...]$12 = Struct { x: 879 }
+// lldbg-check:[...]$12 = Struct { x: 879 }
+// lldbr-check:(self_in_generic_default_method::Struct) *self = Struct { x: 879 }
// lldb-command:print arg1
-// lldb-check:[...]$13 = -9
+// lldbg-check:[...]$13 = -9
+// lldbr-check:(isize) arg1 = -9
// lldb-command:print arg2
-// lldb-check:[...]$14 = -10.5
+// lldbg-check:[...]$14 = -10.5
+// lldbr-check:(f32) arg2 = -10.5
// lldb-command:continue
#![feature(box_syntax)]
// lldb-command:run
// lldb-command:print x
-// lldb-check:[...]$0 = false
+// lldbg-check:[...]$0 = false
+// lldbr-check:(bool) x = false
// lldb-command:print y
-// lldb-check:[...]$1 = true
+// lldbg-check:[...]$1 = true
+// lldbr-check:(bool) y = true
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$2 = 10
+// lldbg-check:[...]$2 = 10
+// lldbr-check:(i32) x = 10
// lldb-command:print y
-// lldb-check:[...]$3 = true
+// lldbg-check:[...]$3 = true
+// lldbr-check:(bool) y = true
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$4 = 10.5
+// lldbg-check:[...]$4 = 10.5
+// lldbr-check:(f64) x = 10.5
// lldb-command:print y
-// lldb-check:[...]$5 = 20
+// lldbg-check:[...]$5 = 20
+// lldbr-check:(i32) y = 20
// lldb-command:continue
// lldb-command:run
// lldb-command:print x
-// lldb-check:[...]$0 = false
+// lldbg-check:[...]$0 = false
+// lldbr-check:(bool) x = false
// lldb-command:print y
-// lldb-check:[...]$1 = true
+// lldbg-check:[...]$1 = true
+// lldbr-check:(bool) y = true
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$2 = 10
+// lldbg-check:[...]$2 = 10
+// lldbr-check:(i32) x = 10
// lldb-command:print y
-// lldb-check:[...]$3 = true
+// lldbg-check:[...]$3 = true
+// lldbr-check:(bool) y = true
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$4 = 10.5
+// lldbg-check:[...]$4 = 10.5
+// lldbr-check:(f64) x = 10.5
// lldb-command:print y
-// lldb-check:[...]$5 = 20
+// lldbg-check:[...]$5 = 20
+// lldbr-check:(i32) y = 20
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$6 = 10.5
+// lldbg-check:[...]$6 = 10.5
+// lldbr-check:(f64) x = 10.5
// lldb-command:print y
-// lldb-check:[...]$7 = 20
+// lldbg-check:[...]$7 = 20
+// lldbr-check:(i32) y = 20
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$8 = 11.5
+// lldbg-check:[...]$8 = 11.5
+// lldbr-check:(f64) x = 11.5
// lldb-command:print y
-// lldb-check:[...]$9 = 20
+// lldbg-check:[...]$9 = 20
+// lldbr-check:(i32) y = 20
// lldb-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print x
-// lldb-check:[...]$0 = false
+// lldbg-check:[...]$0 = false
+// lldbr-check:(bool) x = false
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$1 = false
+// lldbg-check:[...]$1 = false
+// lldbr-check:(bool) x = false
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$2 = 10
+// lldbg-check:[...]$2 = 10
+// lldbr-check:(i32) x = 10
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$3 = 10
+// lldbg-check:[...]$3 = 10
+// lldbr-check:(i32) x = 10
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$4 = 10.5
+// lldbg-check:[...]$4 = 10.5
+// lldbr-check:(f64) x = 10.5
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$5 = 10
+// lldbg-check:[...]$5 = 10
+// lldbr-check:(i32) x = 10
// lldb-command:continue
// lldb-command:print x
-// lldb-check:[...]$6 = false
+// lldbg-check:[...]$6 = false
+// lldbr-check:(bool) x = false
// lldb-command:continue
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-tidy-linelength
+
// min-lldb-version: 310
// ignore-gdb // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
// lldb-command:run
// lldb-command:print no_padding16
-// lldb-check:[...]$0 = NoPadding16 { x: 10000, y: -10001 }
+// lldbg-check:[...]$0 = NoPadding16 { x: 10000, y: -10001 }
+// lldbr-check:(simple_struct::NoPadding16) no_padding16 = NoPadding16 { x: 10000, y: -10001 }
// lldb-command:print no_padding32
-// lldb-check:[...]$1 = NoPadding32 { x: -10002, y: -10003.5, z: 10004 }
+// lldbg-check:[...]$1 = NoPadding32 { x: -10002, y: -10003.5, z: 10004 }
+// lldbr-check:(simple_struct::NoPadding32) no_padding32 = NoPadding32 { x: -10002, y: -10003.5, z: 10004 }
// lldb-command:print no_padding64
-// lldb-check:[...]$2 = NoPadding64 { x: -10005.5, y: 10006, z: 10007 }
+// lldbg-check:[...]$2 = NoPadding64 { x: -10005.5, y: 10006, z: 10007 }
+// lldbr-check:(simple_struct::NoPadding64) no_padding64 = NoPadding64 { x: -10005.5, y: 10006, z: 10007 }
// lldb-command:print no_padding163264
-// lldb-check:[...]$3 = NoPadding163264 { a: -10008, b: 10009, c: 10010, d: 10011 }
+// lldbg-check:[...]$3 = NoPadding163264 { a: -10008, b: 10009, c: 10010, d: 10011 }
+// lldbr-check:(simple_struct::NoPadding163264) no_padding163264 = NoPadding163264 { a: -10008, b: 10009, c: 10010, d: 10011 }
// lldb-command:print internal_padding
-// lldb-check:[...]$4 = InternalPadding { x: 10012, y: -10013 }
+// lldbg-check:[...]$4 = InternalPadding { x: 10012, y: -10013 }
+// lldbr-check:(simple_struct::InternalPadding) internal_padding = InternalPadding { x: 10012, y: -10013 }
// lldb-command:print padding_at_end
-// lldb-check:[...]$5 = PaddingAtEnd { x: -10014, y: 10015 }
+// lldbg-check:[...]$5 = PaddingAtEnd { x: -10014, y: 10015 }
+// lldbr-check:(simple_struct::PaddingAtEnd) padding_at_end = PaddingAtEnd { x: -10014, y: 10015 }
#![allow(unused_variables)]
#![allow(dead_code)]
// lldb-command:run
// lldb-command:print/d noPadding8
-// lldb-check:[...]$0 = (-100, 100)
+// lldbg-check:[...]$0 = (-100, 100)
+// lldbr-check:((i8, u8)) noPadding8 = { = -100 -100 = 100 100 }
// lldb-command:print noPadding16
-// lldb-check:[...]$1 = (0, 1, 2)
+// lldbg-check:[...]$1 = (0, 1, 2)
+// lldbr-check:((i16, i16, u16)) noPadding16 = { = 0 = 1 = 2 }
// lldb-command:print noPadding32
-// lldb-check:[...]$2 = (3, 4.5, 5)
+// lldbg-check:[...]$2 = (3, 4.5, 5)
+// lldbr-check:((i32, f32, u32)) noPadding32 = { = 3 = 4.5 = 5 }
// lldb-command:print noPadding64
-// lldb-check:[...]$3 = (6, 7.5, 8)
+// lldbg-check:[...]$3 = (6, 7.5, 8)
+// lldbr-check:((i64, f64, u64)) noPadding64 = { = 6 = 7.5 = 8 }
// lldb-command:print internalPadding1
-// lldb-check:[...]$4 = (9, 10)
+// lldbg-check:[...]$4 = (9, 10)
+// lldbr-check:((i16, i32)) internalPadding1 = { = 9 = 10 }
// lldb-command:print internalPadding2
-// lldb-check:[...]$5 = (11, 12, 13, 14)
+// lldbg-check:[...]$5 = (11, 12, 13, 14)
+// lldbr-check:((i16, i32, u32, u64)) internalPadding2 = { = 11 = 12 = 13 = 14 }
// lldb-command:print paddingAtEnd
-// lldb-check:[...]$6 = (15, 16)
+// lldbg-check:[...]$6 = (15, 16)
+// lldbr-check:((i32, i16)) paddingAtEnd = { = 15 = 16 }
#![allow(unused_variables)]
#![allow(dead_code)]
// STRUCT
// lldb-command:print arg1
-// lldb-check:[...]$0 = 1
+// lldbg-check:[...]$0 = 1
+// lldbr-check:(isize) arg1 = 1
// lldb-command:print arg2
-// lldb-check:[...]$1 = 2
+// lldbg-check:[...]$1 = 2
+// lldbr-check:(isize) arg2 = 2
// lldb-command:continue
// ENUM
// lldb-command:print arg1
-// lldb-check:[...]$2 = -3
+// lldbg-check:[...]$2 = -3
+// lldbr-check:(isize) arg1 = -3
// lldb-command:print arg2
-// lldb-check:[...]$3 = 4.5
+// lldbg-check:[...]$3 = 4.5
+// lldbr-check:(f64) arg2 = 4.5
// lldb-command:print arg3
-// lldb-check:[...]$4 = 5
+// lldbg-check:[...]$4 = 5
+// lldbr-check:(usize) arg3 = 5
// lldb-command:continue
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print three_simple_structs
-// lldb-check:[...]$0 = ThreeSimpleStructs { x: Simple { x: 1 }, y: Simple { x: 2 }, z: Simple { x: 3 } }
+// lldbg-check:[...]$0 = ThreeSimpleStructs { x: Simple { x: 1 }, y: Simple { x: 2 }, z: Simple { x: 3 } }
+// lldbr-check:(struct_in_struct::ThreeSimpleStructs) three_simple_structs = ThreeSimpleStructs { x: Simple { x: 1 }, y: Simple { x: 2 }, z: Simple { x: 3 } }
// lldb-command:print internal_padding_parent
-// lldb-check:[...]$1 = InternalPaddingParent { x: InternalPadding { x: 4, y: 5 }, y: InternalPadding { x: 6, y: 7 }, z: InternalPadding { x: 8, y: 9 } }
+// lldbg-check:[...]$1 = InternalPaddingParent { x: InternalPadding { x: 4, y: 5 }, y: InternalPadding { x: 6, y: 7 }, z: InternalPadding { x: 8, y: 9 } }
+// lldbr-check:(struct_in_struct::InternalPaddingParent) internal_padding_parent = InternalPaddingParent { x: InternalPadding { x: 4, y: 5 }, y: InternalPadding { x: 6, y: 7 }, z: InternalPadding { x: 8, y: 9 } }
// lldb-command:print padding_at_end_parent
-// lldb-check:[...]$2 = PaddingAtEndParent { x: PaddingAtEnd { x: 10, y: 11 }, y: PaddingAtEnd { x: 12, y: 13 }, z: PaddingAtEnd { x: 14, y: 15 } }
+// lldbg-check:[...]$2 = PaddingAtEndParent { x: PaddingAtEnd { x: 10, y: 11 }, y: PaddingAtEnd { x: 12, y: 13 }, z: PaddingAtEnd { x: 14, y: 15 } }
+// lldbr-check:(struct_in_struct::PaddingAtEndParent) padding_at_end_parent = PaddingAtEndParent { x: PaddingAtEnd { x: 10, y: 11 }, y: PaddingAtEnd { x: 12, y: 13 }, z: PaddingAtEnd { x: 14, y: 15 } }
// lldb-command:print mixed
-// lldb-check:[...]$3 = Mixed { x: PaddingAtEnd { x: 16, y: 17 }, y: InternalPadding { x: 18, y: 19 }, z: Simple { x: 20 }, w: 21 }
+// lldbg-check:[...]$3 = Mixed { x: PaddingAtEnd { x: 16, y: 17 }, y: InternalPadding { x: 18, y: 19 }, z: Simple { x: 20 }, w: 21 }
+// lldbr-check:(struct_in_struct::Mixed) mixed = Mixed { x: PaddingAtEnd { x: 16, y: 17 }, y: InternalPadding { x: 18, y: 19 }, z: Simple { x: 20 }, w: 21 }
// lldb-command:print bag
-// lldb-check:[...]$4 = Bag { x: Simple { x: 22 } }
+// lldbg-check:[...]$4 = Bag { x: Simple { x: 22 } }
+// lldbr-check:(struct_in_struct::Bag) bag = Bag { x: Simple { x: 22 } }
// lldb-command:print bag_in_bag
-// lldb-check:[...]$5 = BagInBag { x: Bag { x: Simple { x: 23 } } }
+// lldbg-check:[...]$5 = BagInBag { x: Bag { x: Simple { x: 23 } } }
+// lldbr-check:(struct_in_struct::BagInBag) bag_in_bag = BagInBag { x: Bag { x: Simple { x: 23 } } }
// lldb-command:print tjo
-// lldb-check:[...]$6 = ThatsJustOverkill { x: BagInBag { x: Bag { x: Simple { x: 24 } } } }
+// lldbg-check:[...]$6 = ThatsJustOverkill { x: BagInBag { x: Bag { x: Simple { x: 24 } } } }
+// lldbr-check:(struct_in_struct::ThatsJustOverkill) tjo = ThatsJustOverkill { x: BagInBag { x: Bag { x: Simple { x: 24 } } } }
// lldb-command:print tree
-// lldb-check:[...]$7 = Tree { x: Simple { x: 25 }, y: InternalPaddingParent { x: InternalPadding { x: 26, y: 27 }, y: InternalPadding { x: 28, y: 29 }, z: InternalPadding { x: 30, y: 31 } }, z: BagInBag { x: Bag { x: Simple { x: 32 } } } }
+// lldbg-check:[...]$7 = Tree { x: Simple { x: 25 }, y: InternalPaddingParent { x: InternalPadding { x: 26, y: 27 }, y: InternalPadding { x: 28, y: 29 }, z: InternalPadding { x: 30, y: 31 } }, z: BagInBag { x: Bag { x: Simple { x: 32 } } } }
+// lldbr-check:(struct_in_struct::Tree) tree = Tree { x: Simple { x: 25 }, y: InternalPaddingParent { x: InternalPadding { x: 26, y: 27 }, y: InternalPadding { x: 28, y: 29 }, z: InternalPadding { x: 30, y: 31 } }, z: BagInBag { x: Bag { x: Simple { x: 32 } } } }
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:p struct1
-// lldb-check:(struct_namespace::Struct1) $0 = [...]
+// lldbg-check:(struct_namespace::Struct1) $0 = [...]
+// lldbr-check:(struct_namespace::Struct1) struct1 = Struct1 { a: 0, b: 1 }
// lldb-command:p struct2
-// lldb-check:(struct_namespace::Struct2) $1 = [...]
+// lldbg-check:(struct_namespace::Struct2) $1 = [...]
+// lldbr-check:(struct_namespace::Struct2) struct2 = { = 2 }
// lldb-command:p mod1_struct1
-// lldb-check:(struct_namespace::mod1::Struct1) $2 = [...]
+// lldbg-check:(struct_namespace::mod1::Struct1) $2 = [...]
+// lldbr-check:(struct_namespace::mod1::Struct1) mod1_struct1 = Struct1 { a: 3, b: 4 }
// lldb-command:p mod1_struct2
-// lldb-check:(struct_namespace::mod1::Struct2) $3 = [...]
+// lldbg-check:(struct_namespace::mod1::Struct2) $3 = [...]
+// lldbr-check:(struct_namespace::mod1::Struct2) mod1_struct2 = { = 5 }
#![allow(unused_variables)]
#![allow(dead_code)]
// lldb-command:run
// lldb-command:print case1
-// lldb-check:[...]$0 = Case1 { a: 0, b: 31868, c: 31868, d: 31868, e: 31868 }
+// lldbg-check:[...]$0 = Case1 { a: 0, b: 31868, c: 31868, d: 31868, e: 31868 }
+// lldbr-check:(struct_style_enum::Regular::Case1) case1 = { a = 0 b = 31868 c = 31868 d = 31868 e = 31868 }
// lldb-command:print case2
-// lldb-check:[...]$1 = Case2 { a: 0, b: 286331153, c: 286331153 }
+// lldbg-check:[...]$1 = Case2 { a: 0, b: 286331153, c: 286331153 }
+// lldbr-check:(struct_style_enum::Regular::Case2) case2 = Case2 { struct_style_enum::Regular::Case1: 0, struct_style_enum::Regular::Case2: 286331153, struct_style_enum::Regular::Case3: 286331153 }
// lldb-command:print case3
-// lldb-check:[...]$2 = Case3 { a: 0, b: 6438275382588823897 }
+// lldbg-check:[...]$2 = Case3 { a: 0, b: 6438275382588823897 }
+// lldbr-check:(struct_style_enum::Regular::Case3) case3 = Case3 { struct_style_enum::Regular::Case1: 0, struct_style_enum::Regular::Case2: 6438275382588823897 }
// lldb-command:print univariant
-// lldb-check:[...]$3 = TheOnlyCase { a: -1 }
+// lldbg-check:[...]$3 = TheOnlyCase { a: -1 }
+// lldbr-check:(struct_style_enum::Univariant) univariant = Univariant { struct_style_enum::TheOnlyCase: TheOnlyCase { a: -1 } }
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print simple
-// lldb-check:[...]$0 = WithDestructor { x: 10, y: 20 }
+// lldbg-check:[...]$0 = WithDestructor { x: 10, y: 20 }
+// lldbr-check:(struct_with_destructor::WithDestructor) simple = WithDestructor { x: 10, y: 20 }
// lldb-command:print noDestructor
-// lldb-check:[...]$1 = NoDestructorGuarded { a: NoDestructor { x: 10, y: 20 }, guard: -1 }
+// lldbg-check:[...]$1 = NoDestructorGuarded { a: NoDestructor { x: 10, y: 20 }, guard: -1 }
+// lldbr-check:(struct_with_destructor::NoDestructorGuarded) noDestructor = NoDestructorGuarded { a: NoDestructor { x: 10, y: 20 }, guard: -1 }
// lldb-command:print withDestructor
-// lldb-check:[...]$2 = WithDestructorGuarded { a: WithDestructor { x: 10, y: 20 }, guard: -1 }
+// lldbg-check:[...]$2 = WithDestructorGuarded { a: WithDestructor { x: 10, y: 20 }, guard: -1 }
+// lldbr-check:(struct_with_destructor::WithDestructorGuarded) withDestructor = WithDestructorGuarded { a: WithDestructor { x: 10, y: 20 }, guard: -1 }
// lldb-command:print nested
-// lldb-check:[...]$3 = NestedOuter { a: NestedInner { a: WithDestructor { x: 7890, y: 9870 } } }
+// lldbg-check:[...]$3 = NestedOuter { a: NestedInner { a: WithDestructor { x: 7890, y: 9870 } } }
+// lldbr-check:(struct_with_destructor::NestedOuter) nested = NestedOuter { a: NestedInner { a: WithDestructor { x: 7890, y: 9870 } } }
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print no_padding1
-// lldb-check:[...]$0 = ((0, 1), 2, 3)
+// lldbg-check:[...]$0 = ((0, 1), 2, 3)
+// lldbr-check:(((u32, u32), u32, u32)) no_padding1 = { = { = 0 = 1 } = 2 = 3 }
// lldb-command:print no_padding2
-// lldb-check:[...]$1 = (4, (5, 6), 7)
+// lldbg-check:[...]$1 = (4, (5, 6), 7)
+// lldbr-check:((u32, (u32, u32), u32)) no_padding2 = { = 4 = { = 5 = 6 } = 7 }
// lldb-command:print no_padding3
-// lldb-check:[...]$2 = (8, 9, (10, 11))
+// lldbg-check:[...]$2 = (8, 9, (10, 11))
+// lldbr-check:((u32, u32, (u32, u32))) no_padding3 = { = 8 = 9 = { = 10 = 11 } }
// lldb-command:print internal_padding1
-// lldb-check:[...]$3 = (12, (13, 14))
+// lldbg-check:[...]$3 = (12, (13, 14))
+// lldbr-check:((i16, (i32, i32))) internal_padding1 = { = 12 = { = 13 = 14 } }
// lldb-command:print internal_padding2
-// lldb-check:[...]$4 = (15, (16, 17))
+// lldbg-check:[...]$4 = (15, (16, 17))
+// lldbr-check:((i16, (i16, i32))) internal_padding2 = { = 15 = { = 16 = 17 } }
// lldb-command:print padding_at_end1
-// lldb-check:[...]$5 = (18, (19, 20))
+// lldbg-check:[...]$5 = (18, (19, 20))
+// lldbr-check:((i32, (i32, i16))) padding_at_end1 = { = 18 = { = 19 = 20 } }
// lldb-command:print padding_at_end2
-// lldb-check:[...]$6 = ((21, 22), 23)
+// lldbg-check:[...]$6 = ((21, 22), 23)
+// lldbr-check:(((i32, i16), i32)) padding_at_end2 = { = { = 21 = 22 } = 23 }
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-tidy-linelength
+
// min-lldb-version: 310
// compile-flags:-g
// lldb-command:run
// lldb-command:print no_padding16
-// lldb-check:[...]$0 = NoPadding16(10000, -10001)
+// lldbg-check:[...]$0 = NoPadding16(10000, -10001)
+// lldbr-check:(tuple_struct::NoPadding16) no_padding16 = { = 10000 = -10001 }
// lldb-command:print no_padding32
-// lldb-check:[...]$1 = NoPadding32(-10002, -10003.5, 10004)
+// lldbg-check:[...]$1 = NoPadding32(-10002, -10003.5, 10004)
+// lldbr-check:(tuple_struct::NoPadding32) no_padding32 = { = -10002 = -10003.5 = 10004 }
// lldb-command:print no_padding64
-// lldb-check:[...]$2 = NoPadding64(-10005.5, 10006, 10007)
+// lldbg-check:[...]$2 = NoPadding64(-10005.5, 10006, 10007)
+// lldbr-check:(tuple_struct::NoPadding64) no_padding64 = { = -10005.5 = 10006 = 10007 }
// lldb-command:print no_padding163264
-// lldb-check:[...]$3 = NoPadding163264(-10008, 10009, 10010, 10011)
+// lldbg-check:[...]$3 = NoPadding163264(-10008, 10009, 10010, 10011)
+// lldbr-check:(tuple_struct::NoPadding163264) no_padding163264 = { = -10008 = 10009 = 10010 = 10011 }
// lldb-command:print internal_padding
-// lldb-check:[...]$4 = InternalPadding(10012, -10013)
+// lldbg-check:[...]$4 = InternalPadding(10012, -10013)
+// lldbr-check:(tuple_struct::InternalPadding) internal_padding = { = 10012 = -10013 }
// lldb-command:print padding_at_end
-// lldb-check:[...]$5 = PaddingAtEnd(-10014, 10015)
+// lldbg-check:[...]$5 = PaddingAtEnd(-10014, 10015)
+// lldbr-check:(tuple_struct::PaddingAtEnd) padding_at_end = { = -10014 = 10015 }
// This test case mainly makes sure that no field names are generated for tuple structs (as opposed
// to all fields having the name "<unnamed_field>"). Otherwise they are handled the same a normal
// lldb-command:run
// lldb-command:print case1
-// lldb-check:[...]$0 = Case1(0, 31868, 31868, 31868, 31868)
+// lldbg-check:[...]$0 = Case1(0, 31868, 31868, 31868, 31868)
+// lldbr-check:(tuple_style_enum::Regular::Case1) case1 = { = 0 = 31868 = 31868 = 31868 = 31868 }
// lldb-command:print case2
-// lldb-check:[...]$1 = Case2(0, 286331153, 286331153)
+// lldbg-check:[...]$1 = Case2(0, 286331153, 286331153)
+// lldbr-check:(tuple_style_enum::Regular::Case2) case2 = Case2 { tuple_style_enum::Regular::Case1: 0, tuple_style_enum::Regular::Case2: 286331153, tuple_style_enum::Regular::Case3: 286331153 }
// lldb-command:print case3
-// lldb-check:[...]$2 = Case3(0, 6438275382588823897)
+// lldbg-check:[...]$2 = Case3(0, 6438275382588823897)
+// lldbr-check:(tuple_style_enum::Regular::Case3) case3 = Case3 { tuple_style_enum::Regular::Case1: 0, tuple_style_enum::Regular::Case2: 6438275382588823897 }
// lldb-command:print univariant
-// lldb-check:[...]$3 = TheOnlyCase(-1)
+// lldbg-check:[...]$3 = TheOnlyCase(-1)
+// lldbr-check:(tuple_style_enum::Univariant) univariant = { tuple_style_enum::TheOnlyCase = { = -1 } }
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print u
-// lldb-check:[...]$0 = U { a: ('\x02', '\x02'), b: 514 }
-// lldb-command:print union_smoke::SU
-// lldb-check:[...]$1 = U { a: ('\x01', '\x01'), b: 257 }
+// lldbg-check:[...]$0 = U { a: ('\x02', '\x02'), b: 514 }
+// lldbr-check:(union_smoke::U) u = { a = { = 2 = 2 } b = 514 }
+
+// Don't test this with rust-enabled lldb for now; see
+// https://github.com/rust-lang-nursery/lldb/issues/18
+// lldbg-command:print union_smoke::SU
+// lldbg-check:[...]$1 = U { a: ('\x01', '\x01'), b: 257 }
#![allow(unused)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print *the_a
-// lldb-check:[...]$0 = TheA { x: 0, y: 8970181431921507452 }
+// lldbg-check:[...]$0 = TheA { x: 0, y: 8970181431921507452 }
+// lldbr-check:(unique_enum::ABC::TheA) *the_a = TheA { unique_enum::ABC::TheA: 0, unique_enum::ABC::TheB: 8970181431921507452 }
// lldb-command:print *the_b
-// lldb-check:[...]$1 = TheB(0, 286331153, 286331153)
+// lldbg-check:[...]$1 = TheB(0, 286331153, 286331153)
+// lldbr-check:(unique_enum::ABC::TheB) *the_b = { = 0 = 286331153 = 286331153 }
// lldb-command:print *univariant
-// lldb-check:[...]$2 = TheOnlyCase(123234)
+// lldbg-check:[...]$2 = TheOnlyCase(123234)
+// lldbr-check:(unique_enum::Univariant) *univariant = { unique_enum::TheOnlyCase = { = 123234 } }
#![allow(unused_variables)]
#![feature(box_syntax)]
// lldb-command:run
// lldb-command:print variable
-// lldb-check:[...]$0 = 1
+// lldbg-check:[...]$0 = 1
+// lldbr-check:(isize) variable = 1
// lldb-command:print constant
-// lldb-check:[...]$1 = 2
+// lldbg-check:[...]$1 = 2
+// lldbr-check:(isize) constant = 2
// lldb-command:print a_struct
-// lldb-check:[...]$2 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbg-check:[...]$2 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbr-check:(var_captured_in_nested_closure::Struct) a_struct = Struct { a: -3, b: 4.5, c: 5 }
// lldb-command:print *struct_ref
-// lldb-check:[...]$3 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbg-check:[...]$3 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbr-check:(var_captured_in_nested_closure::Struct) *struct_ref = Struct { a: -3, b: 4.5, c: 5 }
// lldb-command:print *owned
-// lldb-check:[...]$4 = 6
+// lldbg-check:[...]$4 = 6
+// lldbr-check:(isize) *owned = 6
// lldb-command:print closure_local
-// lldb-check:[...]$5 = 8
+// lldbg-check:[...]$5 = 8
+// lldbr-check:(isize) closure_local = 8
// lldb-command:continue
// lldb-command:print variable
-// lldb-check:[...]$6 = 1
+// lldbg-check:[...]$6 = 1
+// lldbr-check:(isize) variable = 1
// lldb-command:print constant
-// lldb-check:[...]$7 = 2
+// lldbg-check:[...]$7 = 2
+// lldbr-check:(isize) constant = 2
// lldb-command:print a_struct
-// lldb-check:[...]$8 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbg-check:[...]$8 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbr-check:(var_captured_in_nested_closure::Struct) a_struct = Struct { a: -3, b: 4.5, c: 5 }
// lldb-command:print *struct_ref
-// lldb-check:[...]$9 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbg-check:[...]$9 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbr-check:(var_captured_in_nested_closure::Struct) *struct_ref = Struct { a: -3, b: 4.5, c: 5 }
// lldb-command:print *owned
-// lldb-check:[...]$10 = 6
+// lldbg-check:[...]$10 = 6
+// lldbr-check:(isize) *owned = 6
// lldb-command:print closure_local
-// lldb-check:[...]$11 = 8
+// lldbg-check:[...]$11 = 8
+// lldbr-check:(isize) closure_local = 8
// lldb-command:continue
#![allow(unused_variables)]
// lldb-command:run
// lldb-command:print constant
-// lldb-check:[...]$0 = 1
+// lldbg-check:[...]$0 = 1
+// lldbr-check:(isize) constant = 1
// lldb-command:print a_struct
-// lldb-check:[...]$1 = Struct { a: -2, b: 3.5, c: 4 }
+// lldbg-check:[...]$1 = Struct { a: -2, b: 3.5, c: 4 }
+// lldbr-check:(var_captured_in_sendable_closure::Struct) a_struct = Struct { a: -2, b: 3.5, c: 4 }
// lldb-command:print *owned
-// lldb-check:[...]$2 = 5
+// lldbg-check:[...]$2 = 5
+// lldbr-check:(isize) *owned = 5
#![allow(unused_variables)]
#![feature(box_syntax)]
// lldb-command:run
// lldb-command:print variable
-// lldb-check:[...]$0 = 1
+// lldbg-check:[...]$0 = 1
+// lldbr-check:(isize) variable = 1
// lldb-command:print constant
-// lldb-check:[...]$1 = 2
+// lldbg-check:[...]$1 = 2
+// lldbr-check:(isize) constant = 2
// lldb-command:print a_struct
-// lldb-check:[...]$2 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbg-check:[...]$2 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbr-check:(var_captured_in_stack_closure::Struct) a_struct = Struct { a: -3, b: 4.5, c: 5 }
// lldb-command:print *struct_ref
-// lldb-check:[...]$3 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbg-check:[...]$3 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbr-check:(var_captured_in_stack_closure::Struct) *struct_ref = Struct { a: -3, b: 4.5, c: 5 }
// lldb-command:print *owned
-// lldb-check:[...]$4 = 6
+// lldbg-check:[...]$4 = 6
+// lldbr-check:(isize) *owned = 6
// lldb-command:continue
// lldb-command:print variable
-// lldb-check:[...]$5 = 2
+// lldbg-check:[...]$5 = 2
+// lldbr-check:(isize) variable = 2
// lldb-command:print constant
-// lldb-check:[...]$6 = 2
+// lldbg-check:[...]$6 = 2
+// lldbr-check:(isize) constant = 2
// lldb-command:print a_struct
-// lldb-check:[...]$7 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbg-check:[...]$7 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbr-check:(var_captured_in_stack_closure::Struct) a_struct = Struct { a: -3, b: 4.5, c: 5 }
// lldb-command:print *struct_ref
-// lldb-check:[...]$8 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbg-check:[...]$8 = Struct { a: -3, b: 4.5, c: 5 }
+// lldbr-check:(var_captured_in_stack_closure::Struct) *struct_ref = Struct { a: -3, b: 4.5, c: 5 }
// lldb-command:print *owned
-// lldb-check:[...]$9 = 6
+// lldbg-check:[...]$9 = 6
+// lldbr-check:(isize) *owned = 6
#![feature(box_syntax)]
#![allow(unused_variables)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// ignore-tidy-linelength
+
// ignore-windows
// ignore-gdb // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
// min-lldb-version: 310
// lldb-command:run
// lldb-command:print empty
-// lldb-check:[...]$0 = &[]
+// lldbg-check:[...]$0 = &[]
+// lldbr-check:(&[i64]) empty = &[]
// lldb-command:print singleton
-// lldb-check:[...]$1 = &[1]
+// lldbg-check:[...]$1 = &[1]
+// lldbr-check:(&[i64]) singleton = &[1]
// lldb-command:print multiple
-// lldb-check:[...]$2 = &[2, 3, 4, 5]
+// lldbg-check:[...]$2 = &[2, 3, 4, 5]
+// lldbr-check:(&[i64]) multiple = &[2, 3, 4, 5]
// lldb-command:print slice_of_slice
-// lldb-check:[...]$3 = &[3, 4]
+// lldbg-check:[...]$3 = &[3, 4]
+// lldbr-check:(&[i64]) slice_of_slice = &[3, 4]
// lldb-command:print padded_tuple
-// lldb-check:[...]$4 = &[(6, 7), (8, 9)]
+// lldbg-check:[...]$4 = &[(6, 7), (8, 9)]
+// lldbr-check:(&[(i32, i16)]) padded_tuple = { data_ptr = *0x555555554ff0 length = 2 }
// lldb-command:print padded_struct
-// lldb-check:[...]$5 = &[AStruct { x: 10, y: 11, z: 12 }, AStruct { x: 13, y: 14, z: 15 }]
+// lldbg-check:[...]$5 = &[AStruct { x: 10, y: 11, z: 12 }, AStruct { x: 13, y: 14, z: 15 }]
+// lldbr-check:(&[vec_slices::AStruct]) padded_struct = &[AStruct { x: 10, y: 11, z: 12 }, AStruct { x: 13, y: 14, z: 15 }]
#![allow(dead_code, unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
// lldb-command:run
// lldb-command:print a
-// lldb-check:[...]$0 = [1, 2, 3]
+// lldbg-check:[...]$0 = [1, 2, 3]
+// lldbr-check:([i32; 3]) a = [1, 2, 3]
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
--> $DIR/const-pointer-values-in-various-types.rs:24:5
|
LL | const I32_REF_USIZE_UNION: usize = unsafe { Nonsense { int_32_ref: &3 }.u };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected the type usize
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
--> $DIR/const-pointer-values-in-various-types.rs:36:5
|
LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected the type u64
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
--> $DIR/const-pointer-values-in-various-types.rs:51:5
|
LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected the type i64
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
--> $DIR/const-pointer-values-in-various-types.rs:60:5
|
LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected the type f64
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
--> $DIR/const-pointer-values-in-various-types.rs:78:5
|
LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected the type u64
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
--> $DIR/const-pointer-values-in-various-types.rs:93:5
|
LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected the type i64
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
--> $DIR/const-pointer-values-in-various-types.rs:102:5
|
LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected the type f64
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
static FOO: bool = unsafe { mem::transmute(3u8) };
//~^ ERROR this static likely exhibits undefined behavior
-//~^^ type validation failed: encountered 3, but expected something in the range 0..=1
fn main() {}
--> $DIR/ub-enum.rs:45:1
|
LL | const BAD_ENUM_CHAR : Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b }));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered character at .Some.0.1, but expected a valid unicode codepoint
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at .Some.0.1, but expected something in the range 0..=1114111
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(const_transmute)]
+
+use std::mem;
+use std::ptr::NonNull;
+use std::num::{NonZeroU8, NonZeroUsize};
+
+const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
+//~^ ERROR this constant likely exhibits undefined behavior
+
+const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
+//~^ ERROR this constant likely exhibits undefined behavior
+const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
+//~^ ERROR this constant likely exhibits undefined behavior
+
+fn main() {}
--- /dev/null
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/ub-nonnull.rs:17:1
+ |
+LL | const NULL_PTR: NonNull<u8> = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/ub-nonnull.rs:20:1
+ |
+LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/ub-nonnull.rs:22:1
+ |
+LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(const_transmute)]
+
+use std::mem;
+
+const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
+//~^ ERROR this constant likely exhibits undefined behavior
+
+const NULL: &u16 = unsafe { mem::transmute(0usize) };
+//~^ ERROR this constant likely exhibits undefined behavior
+
+const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
+//~^ ERROR this constant likely exhibits undefined behavior
+
+const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
+//~^ ERROR this constant likely exhibits undefined behavior
+
+fn main() {}
--- /dev/null
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/ub-ref.rs:15:1
+ |
+LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered unaligned reference
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/ub-ref.rs:18:1
+ |
+LL | const NULL: &u16 = unsafe { mem::transmute(0usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/ub-ref.rs:21:1
+ |
+LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected initialized plain bits
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/ub-ref.rs:24:1
+ |
+LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered integer pointer in non-ZST reference
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-union Foo {
- a: u8,
- b: Bar,
-}
+#![feature(const_transmute)]
+
+use std::mem;
#[derive(Copy, Clone)]
enum Bar {}
-const BAD_BAD_BAD: Bar = unsafe { Foo { a: 1 }.b};
+const BAD_BAD_BAD: Bar = unsafe { mem::transmute(()) };
+//~^ ERROR this constant likely exhibits undefined behavior
+
+const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
+//~^ ERROR this constant likely exhibits undefined behavior
+
+const BAD_BAD_ARRAY: [Bar; 1] = unsafe { mem::transmute(()) };
//~^ ERROR this constant likely exhibits undefined behavior
fn main() {
error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/ub-uninhabit.rs:19:1
+ --> $DIR/ub-uninhabit.rs:18:1
|
-LL | const BAD_BAD_BAD: Bar = unsafe { Foo { a: 1 }.b};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type
+LL | const BAD_BAD_BAD: Bar = unsafe { mem::transmute(()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-error: aborting due to previous error
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/ub-uninhabit.rs:21:1
+ |
+LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at .<deref>
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/ub-uninhabit.rs:24:1
+ |
+LL | const BAD_BAD_ARRAY: [Bar; 1] = unsafe { mem::transmute(()) };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a value of an uninhabited type at [0]
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error: aborting due to 3 previous errors
For more information about this error, try `rustc --explain E0080`.
+++ /dev/null
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-pass
-
-union Foo {
- a: &'static u8,
- b: usize,
-}
-
-// This might point to an invalid address, but that's the user's problem
-const USIZE_AS_STATIC_REF: &'static u8 = unsafe { Foo { b: 1337 }.a};
-
-fn main() {
-}
LL | | a: 42,
LL | | b: unsafe { UNION.field3 },
LL | | };
- | |__^ type validation failed: encountered undefined bytes at .b
+ | |__^ type validation failed: encountered uninitialized bytes at .b, but expected initialized plain bits
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
--- /dev/null
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(unused)]
+
+// normalize-stderr-test "alignment \d+" -> "alignment N"
+// normalize-stderr-test "offset \d+" -> "offset N"
+// normalize-stderr-test "allocation \d+" -> "allocation N"
+// normalize-stderr-test "size \d+" -> "size N"
+
+union BoolTransmute {
+ val: u8,
+ bl: bool,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct SliceRepr {
+ ptr: *const u8,
+ len: usize,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct BadSliceRepr {
+ ptr: *const u8,
+ len: &'static u8,
+}
+
+union SliceTransmute {
+ repr: SliceRepr,
+ bad: BadSliceRepr,
+ slice: &'static [u8],
+ str: &'static str,
+ my_str: &'static MyStr,
+ my_slice: &'static MySliceBool,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct DynRepr {
+ ptr: *const u8,
+ vtable: *const u8,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct DynRepr2 {
+ ptr: *const u8,
+ vtable: *const u64,
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+struct BadDynRepr {
+ ptr: *const u8,
+ vtable: usize,
+}
+
+union DynTransmute {
+ repr: DynRepr,
+ repr2: DynRepr2,
+ bad: BadDynRepr,
+ rust: &'static Trait,
+}
+
+trait Trait {}
+impl Trait for bool {}
+
+// custom unsized type
+struct MyStr(str);
+
+// custom unsized type with sized fields
+struct MySlice<T: ?Sized>(bool, T);
+type MySliceBool = MySlice<[bool]>;
+
+// OK
+const A: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.str};
+// bad str
+const B: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str};
+//~^ ERROR this constant likely exhibits undefined behavior
+// bad str
+const C: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str};
+//~^ ERROR this constant likely exhibits undefined behavior
+// bad str in user-defined unsized type
+const C2: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str};
+//~^ ERROR this constant likely exhibits undefined behavior
+
+// OK
+const A2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.slice};
+// bad slice
+const B2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice};
+//~^ ERROR this constant likely exhibits undefined behavior
+// bad slice
+const C3: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice};
+//~^ ERROR this constant likely exhibits undefined behavior
+
+// bad trait object
+const D: &Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust};
+//~^ ERROR this constant likely exhibits undefined behavior
+// bad trait object
+const E: &Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust};
+//~^ ERROR this constant likely exhibits undefined behavior
+// bad trait object
+const F: &Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust};
+//~^ ERROR this constant likely exhibits undefined behavior
+
+// bad data *inside* the trait object
+const G: &Trait = &unsafe { BoolTransmute { val: 3 }.bl };
+//~^ ERROR this constant likely exhibits undefined behavior
+// bad data *inside* the slice
+const H: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }];
+//~^ ERROR this constant likely exhibits undefined behavior
+
+// good MySliceBool
+const I1: &MySliceBool = &MySlice(true, [false]);
+// bad: sized field is not okay
+const I2: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]);
+//~^ ERROR this constant likely exhibits undefined behavior
+// bad: unsized part is not okay
+const I3: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]);
+//~^ ERROR this constant likely exhibits undefined behavior
+
+// invalid UTF-8
+const J1: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str };
+//~^ ERROR this constant likely exhibits undefined behavior
+// invalid UTF-8 in user-defined str-like
+const J2: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str };
+//~^ ERROR this constant likely exhibits undefined behavior
+
+fn main() {
+}
--- /dev/null
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:87:1
+ |
+LL | const B: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str};
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling (not entirely in bounds) reference
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:90:1
+ |
+LL | const C: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str};
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:93:1
+ |
+LL | const C2: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str};
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:99:1
+ |
+LL | const B2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice};
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling (not entirely in bounds) reference
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:102:1
+ |
+LL | const C3: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice};
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:106:1
+ |
+LL | const D: &Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust};
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop fn in vtable
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:109:1
+ |
+LL | const E: &Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust};
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop fn in vtable
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:112:1
+ |
+LL | const F: &Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust};
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-pointer vtable in fat pointer
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:116:1
+ |
+LL | const G: &Trait = &unsafe { BoolTransmute { val: 3 }.bl };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>, but expected something in the range 0..=1
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:119:1
+ |
+LL | const H: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }];
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>[0], but expected something in the range 0..=1
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:125:1
+ |
+LL | const I2: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.0, but expected something in the range 0..=1
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:128:1
+ |
+LL | const I3: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.1[0], but expected something in the range 0..=1
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:132:1
+ |
+LL | const J1: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at .<deref>
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error[E0080]: this constant likely exhibits undefined behavior
+ --> $DIR/union-ub-fat-ptr.rs:135:1
+ |
+LL | const J2: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or non-UTF-8 data in str at .<deref>.0
+ |
+ = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
+
+error: aborting due to 14 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
const BAD_UNION: Foo = unsafe { Bar { u8: 42 }.foo };
-fn main() {
-}
+fn main() {}
--- /dev/null
+// compile-pass
+
+// Some constants that *are* valid
+#![feature(const_transmute)]
+
+use std::mem;
+use std::ptr::NonNull;
+use std::num::{NonZeroU8, NonZeroUsize};
+
+const NON_NULL_PTR1: NonNull<u8> = unsafe { mem::transmute(1usize) };
+const NON_NULL_PTR2: NonNull<u8> = unsafe { mem::transmute(&0) };
+
+const NON_NULL_U8: NonZeroU8 = unsafe { mem::transmute(1u8) };
+const NON_NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(1usize) };
+
+const UNIT: () = ();
+
+fn main() {}
error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference
--> $DIR/issue-38147-2.rs:17:9
|
+LL | s: &'a String
+ | ---------- help: consider changing this to be mutable: `&'a mut String`
+...
LL | self.s.push('x');
| ^^^^^^ cannot borrow as mutable
error[E0596]: cannot borrow `*self.s` as mutable, as it is behind a `&` reference
--> $DIR/issue-38147-3.rs:17:9
|
+LL | s: &'a String
+ | ---------- help: consider changing this to be mutable: `&'a mut String`
+...
LL | self.s.push('x');
| ^^^^^^ cannot borrow as mutable
#![allow(safe_extern_statics, warnings)]
extern {
- pub static symbol: ();
+ pub static symbol: u32;
}
-static CRASH: () = symbol;
+static CRASH: u32 = symbol;
//~^ ERROR could not evaluate static initializer
//~| tried to read from foreign (extern) static
error[E0080]: could not evaluate static initializer
- --> $DIR/issue-14227.rs:16:20
+ --> $DIR/issue-14227.rs:16:21
|
-LL | static CRASH: () = symbol;
- | ^^^^^^ tried to read from foreign (extern) static
+LL | static CRASH: u32 = symbol;
+ | ^^^^^^ tried to read from foreign (extern) static
error: aborting due to previous error
--- /dev/null
+#![feature(nll)]
+
+enum Foo<'a> {
+ Bar { field: &'a u32 }
+}
+
+fn in_let() {
+ let y = 22;
+ let foo = Foo::Bar { field: &y };
+ //~^ ERROR `y` does not live long enough
+ let Foo::Bar::<'static> { field: _z } = foo;
+}
+
+fn in_match() {
+ let y = 22;
+ let foo = Foo::Bar { field: &y };
+ //~^ ERROR `y` does not live long enough
+ match foo {
+ Foo::Bar::<'static> { field: _z } => {
+ }
+ }
+}
+
+fn main() { }
--- /dev/null
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_brace_enum_variant.rs:9:33
+ |
+LL | let foo = Foo::Bar { field: &y };
+ | ^^ borrowed value does not live long enough
+...
+LL | }
+ | - `y` dropped here while still borrowed
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_brace_enum_variant.rs:16:33
+ |
+LL | let foo = Foo::Bar { field: &y };
+ | ^^ borrowed value does not live long enough
+...
+LL | }
+ | - `y` dropped here while still borrowed
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+#![feature(nll)]
+
+struct Foo<'a> { field: &'a u32 }
+
+fn in_let() {
+ let y = 22;
+ let foo = Foo { field: &y };
+ //~^ ERROR `y` does not live long enough
+ let Foo::<'static> { field: _z } = foo;
+}
+
+fn in_main() {
+ let y = 22;
+ let foo = Foo { field: &y };
+ //~^ ERROR `y` does not live long enough
+ match foo {
+ Foo::<'static> { field: _z } => {
+ }
+ }
+}
+
+fn main() { }
--- /dev/null
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_brace_struct.rs:7:28
+ |
+LL | let foo = Foo { field: &y };
+ | ^^ borrowed value does not live long enough
+...
+LL | }
+ | - `y` dropped here while still borrowed
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_brace_struct.rs:14:28
+ |
+LL | let foo = Foo { field: &y };
+ | ^^ borrowed value does not live long enough
+...
+LL | }
+ | - `y` dropped here while still borrowed
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+#![feature(nll)]
+
+enum Foo<'a> {
+ Bar(&'a u32)
+}
+
+fn in_let() {
+ let y = 22;
+ let foo = Foo::Bar(&y);
+ //~^ ERROR `y` does not live long enough
+ let Foo::Bar::<'static>(_z) = foo;
+}
+
+fn in_match() {
+ let y = 22;
+ let foo = Foo::Bar(&y);
+ //~^ ERROR `y` does not live long enough
+ match foo {
+ Foo::Bar::<'static>(_z) => {
+ }
+ }
+}
+
+fn main() { }
--- /dev/null
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_tuple_enum_variant.rs:9:24
+ |
+LL | let foo = Foo::Bar(&y);
+ | ^^ borrowed value does not live long enough
+...
+LL | }
+ | - `y` dropped here while still borrowed
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_tuple_enum_variant.rs:16:24
+ |
+LL | let foo = Foo::Bar(&y);
+ | ^^ borrowed value does not live long enough
+...
+LL | }
+ | - `y` dropped here while still borrowed
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+#![feature(nll)]
+
+struct Foo<'a>(&'a u32);
+
+fn in_let() {
+ let y = 22;
+ let foo = Foo(&y);
+ //~^ ERROR `y` does not live long enough
+ let Foo::<'static>(_z) = foo;
+}
+
+fn in_match() {
+ let y = 22;
+ let foo = Foo(&y);
+ //~^ ERROR `y` does not live long enough
+ match foo {
+ Foo::<'static>(_z) => {
+ }
+ }
+}
+
+fn main() { }
--- /dev/null
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_tuple_struct.rs:7:19
+ |
+LL | let foo = Foo(&y);
+ | ^^ borrowed value does not live long enough
+...
+LL | }
+ | - `y` dropped here while still borrowed
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error[E0597]: `y` does not live long enough
+ --> $DIR/pattern_substs_on_tuple_struct.rs:14:19
+ |
+LL | let foo = Foo(&y);
+ | ^^ borrowed value does not live long enough
+...
+LL | }
+ | - `y` dropped here while still borrowed
+ |
+ = note: borrowed value must be valid for the static lifetime...
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0597`.
--- /dev/null
+// run-rustfix
+
+// Regression test for changes introduced while fixing #54505
+
+// This test uses non-literals for Ranges
+// (expecting no parens with borrow suggestion)
+
+use std::ops::RangeBounds;
+
+
+// take a reference to any built-in range
+fn take_range(_r: &impl RangeBounds<i8>) {}
+
+
+fn main() {
+ take_range(&std::ops::Range { start: 0, end: 1 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::Range { start: 0, end: 1 }
+
+ take_range(&::std::ops::Range { start: 0, end: 1 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::Range { start: 0, end: 1 }
+
+ take_range(&std::ops::RangeFrom { start: 1 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::RangeFrom { start: 1 }
+
+ take_range(&::std::ops::RangeFrom { start: 1 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::RangeFrom { start: 1 }
+
+ take_range(&std::ops::RangeFull {});
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::RangeFull {}
+
+ take_range(&::std::ops::RangeFull {});
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::RangeFull {}
+
+ take_range(&std::ops::RangeInclusive::new(0, 1));
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::RangeInclusive::new(0, 1)
+
+ take_range(&::std::ops::RangeInclusive::new(0, 1));
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::RangeInclusive::new(0, 1)
+
+ take_range(&std::ops::RangeTo { end: 5 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::RangeTo { end: 5 }
+
+ take_range(&::std::ops::RangeTo { end: 5 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::RangeTo { end: 5 }
+
+ take_range(&std::ops::RangeToInclusive { end: 5 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::RangeToInclusive { end: 5 }
+
+ take_range(&::std::ops::RangeToInclusive { end: 5 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::RangeToInclusive { end: 5 }
+}
--- /dev/null
+// run-rustfix
+
+// Regression test for changes introduced while fixing #54505
+
+// This test uses non-literals for Ranges
+// (expecting no parens with borrow suggestion)
+
+use std::ops::RangeBounds;
+
+
+// take a reference to any built-in range
+fn take_range(_r: &impl RangeBounds<i8>) {}
+
+
+fn main() {
+ take_range(std::ops::Range { start: 0, end: 1 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::Range { start: 0, end: 1 }
+
+ take_range(::std::ops::Range { start: 0, end: 1 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::Range { start: 0, end: 1 }
+
+ take_range(std::ops::RangeFrom { start: 1 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::RangeFrom { start: 1 }
+
+ take_range(::std::ops::RangeFrom { start: 1 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::RangeFrom { start: 1 }
+
+ take_range(std::ops::RangeFull {});
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::RangeFull {}
+
+ take_range(::std::ops::RangeFull {});
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::RangeFull {}
+
+ take_range(std::ops::RangeInclusive::new(0, 1));
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::RangeInclusive::new(0, 1)
+
+ take_range(::std::ops::RangeInclusive::new(0, 1));
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::RangeInclusive::new(0, 1)
+
+ take_range(std::ops::RangeTo { end: 5 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::RangeTo { end: 5 }
+
+ take_range(::std::ops::RangeTo { end: 5 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::RangeTo { end: 5 }
+
+ take_range(std::ops::RangeToInclusive { end: 5 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &std::ops::RangeToInclusive { end: 5 }
+
+ take_range(::std::ops::RangeToInclusive { end: 5 });
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &::std::ops::RangeToInclusive { end: 5 }
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:16:16
+ |
+LL | take_range(std::ops::Range { start: 0, end: 1 });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::Range`
+ | help: consider borrowing here: `&std::ops::Range { start: 0, end: 1 }`
+ |
+ = note: expected type `&_`
+ found type `std::ops::Range<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:21:16
+ |
+LL | take_range(::std::ops::Range { start: 0, end: 1 });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::Range`
+ | help: consider borrowing here: `&::std::ops::Range { start: 0, end: 1 }`
+ |
+ = note: expected type `&_`
+ found type `std::ops::Range<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:26:16
+ |
+LL | take_range(std::ops::RangeFrom { start: 1 });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeFrom`
+ | help: consider borrowing here: `&std::ops::RangeFrom { start: 1 }`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeFrom<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:31:16
+ |
+LL | take_range(::std::ops::RangeFrom { start: 1 });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeFrom`
+ | help: consider borrowing here: `&::std::ops::RangeFrom { start: 1 }`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeFrom<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:36:16
+ |
+LL | take_range(std::ops::RangeFull {});
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeFull`
+ | help: consider borrowing here: `&std::ops::RangeFull {}`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeFull`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:41:16
+ |
+LL | take_range(::std::ops::RangeFull {});
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeFull`
+ | help: consider borrowing here: `&::std::ops::RangeFull {}`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeFull`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:46:16
+ |
+LL | take_range(std::ops::RangeInclusive::new(0, 1));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeInclusive`
+ | help: consider borrowing here: `&std::ops::RangeInclusive::new(0, 1)`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeInclusive<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:51:16
+ |
+LL | take_range(::std::ops::RangeInclusive::new(0, 1));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeInclusive`
+ | help: consider borrowing here: `&::std::ops::RangeInclusive::new(0, 1)`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeInclusive<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:56:16
+ |
+LL | take_range(std::ops::RangeTo { end: 5 });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeTo`
+ | help: consider borrowing here: `&std::ops::RangeTo { end: 5 }`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeTo<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:61:16
+ |
+LL | take_range(::std::ops::RangeTo { end: 5 });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeTo`
+ | help: consider borrowing here: `&::std::ops::RangeTo { end: 5 }`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeTo<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:66:16
+ |
+LL | take_range(std::ops::RangeToInclusive { end: 5 });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeToInclusive`
+ | help: consider borrowing here: `&std::ops::RangeToInclusive { end: 5 }`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeToInclusive<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-literals.rs:71:16
+ |
+LL | take_range(::std::ops::RangeToInclusive { end: 5 });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeToInclusive`
+ | help: consider borrowing here: `&::std::ops::RangeToInclusive { end: 5 }`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeToInclusive<{integer}>`
+
+error: aborting due to 12 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// error-pattern: `#[panic_handler]` function required, but not found
+
+// Regression test for #54505 - range borrowing suggestion had
+// incorrect syntax (missing parentheses).
+
+// This test doesn't use std
+// (so all Ranges resolve to core::ops::Range...)
+
+#![no_std]
+#![feature(lang_items)]
+
+use core::ops::RangeBounds;
+
+#[cfg(not(target_arch = "wasm32"))]
+#[lang = "eh_personality"]
+extern fn eh_personality() {}
+
+#[cfg(target_os = "windows")]
+#[lang = "eh_unwind_resume"]
+extern fn eh_unwind_resume() {}
+
+
+// take a reference to any built-in range
+fn take_range(_r: &impl RangeBounds<i8>) {}
+
+
+fn main() {
+ take_range(0..1);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(0..1)
+
+ take_range(1..);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(1..)
+
+ take_range(..);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(..)
+
+ take_range(0..=1);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(0..=1)
+
+ take_range(..5);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(..5)
+
+ take_range(..=42);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(..=42)
+}
--- /dev/null
+error: `#[panic_handler]` function required, but not found
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-std.rs:28:16
+ |
+LL | take_range(0..1);
+ | ^^^^
+ | |
+ | expected reference, found struct `core::ops::Range`
+ | help: consider borrowing here: `&(0..1)`
+ |
+ = note: expected type `&_`
+ found type `core::ops::Range<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-std.rs:33:16
+ |
+LL | take_range(1..);
+ | ^^^
+ | |
+ | expected reference, found struct `core::ops::RangeFrom`
+ | help: consider borrowing here: `&(1..)`
+ |
+ = note: expected type `&_`
+ found type `core::ops::RangeFrom<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-std.rs:38:16
+ |
+LL | take_range(..);
+ | ^^
+ | |
+ | expected reference, found struct `core::ops::RangeFull`
+ | help: consider borrowing here: `&(..)`
+ |
+ = note: expected type `&_`
+ found type `core::ops::RangeFull`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-std.rs:43:16
+ |
+LL | take_range(0..=1);
+ | ^^^^^
+ | |
+ | expected reference, found struct `core::ops::RangeInclusive`
+ | help: consider borrowing here: `&(0..=1)`
+ |
+ = note: expected type `&_`
+ found type `core::ops::RangeInclusive<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-std.rs:48:16
+ |
+LL | take_range(..5);
+ | ^^^
+ | |
+ | expected reference, found struct `core::ops::RangeTo`
+ | help: consider borrowing here: `&(..5)`
+ |
+ = note: expected type `&_`
+ found type `core::ops::RangeTo<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505-no-std.rs:53:16
+ |
+LL | take_range(..=42);
+ | ^^^^^
+ | |
+ | expected reference, found struct `core::ops::RangeToInclusive`
+ | help: consider borrowing here: `&(..=42)`
+ |
+ = note: expected type `&_`
+ found type `core::ops::RangeToInclusive<{integer}>`
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// run-rustfix
+
+// Regression test for #54505 - range borrowing suggestion had
+// incorrect syntax (missing parentheses).
+
+use std::ops::RangeBounds;
+
+
+// take a reference to any built-in range
+fn take_range(_r: &impl RangeBounds<i8>) {}
+
+
+fn main() {
+ take_range(&(0..1));
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(0..1)
+
+ take_range(&(1..));
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(1..)
+
+ take_range(&(..));
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(..)
+
+ take_range(&(0..=1));
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(0..=1)
+
+ take_range(&(..5));
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(..5)
+
+ take_range(&(..=42));
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(..=42)
+}
--- /dev/null
+// run-rustfix
+
+// Regression test for #54505 - range borrowing suggestion had
+// incorrect syntax (missing parentheses).
+
+use std::ops::RangeBounds;
+
+
+// take a reference to any built-in range
+fn take_range(_r: &impl RangeBounds<i8>) {}
+
+
+fn main() {
+ take_range(0..1);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(0..1)
+
+ take_range(1..);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(1..)
+
+ take_range(..);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(..)
+
+ take_range(0..=1);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(0..=1)
+
+ take_range(..5);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(..5)
+
+ take_range(..=42);
+ //~^ ERROR mismatched types [E0308]
+ //~| HELP consider borrowing here
+ //~| SUGGESTION &(..=42)
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-54505.rs:14:16
+ |
+LL | take_range(0..1);
+ | ^^^^
+ | |
+ | expected reference, found struct `std::ops::Range`
+ | help: consider borrowing here: `&(0..1)`
+ |
+ = note: expected type `&_`
+ found type `std::ops::Range<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505.rs:19:16
+ |
+LL | take_range(1..);
+ | ^^^
+ | |
+ | expected reference, found struct `std::ops::RangeFrom`
+ | help: consider borrowing here: `&(1..)`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeFrom<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505.rs:24:16
+ |
+LL | take_range(..);
+ | ^^
+ | |
+ | expected reference, found struct `std::ops::RangeFull`
+ | help: consider borrowing here: `&(..)`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeFull`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505.rs:29:16
+ |
+LL | take_range(0..=1);
+ | ^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeInclusive`
+ | help: consider borrowing here: `&(0..=1)`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeInclusive<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505.rs:34:16
+ |
+LL | take_range(..5);
+ | ^^^
+ | |
+ | expected reference, found struct `std::ops::RangeTo`
+ | help: consider borrowing here: `&(..5)`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeTo<{integer}>`
+
+error[E0308]: mismatched types
+ --> $DIR/issue-54505.rs:39:16
+ |
+LL | take_range(..=42);
+ | ^^^^^
+ | |
+ | expected reference, found struct `std::ops::RangeToInclusive`
+ | help: consider borrowing here: `&(..=42)`
+ |
+ = note: expected type `&_`
+ found type `std::ops::RangeToInclusive<{integer}>`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![allow(unused)]
-
-// normalize-stderr-test "alignment \d+" -> "alignment N"
-// normalize-stderr-test "offset \d+" -> "offset N"
-// normalize-stderr-test "allocation \d+" -> "allocation N"
-// normalize-stderr-test "size \d+" -> "size N"
-
-union BoolTransmute {
- val: u8,
- bl: bool,
-}
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-struct SliceRepr {
- ptr: *const u8,
- len: usize,
-}
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-struct BadSliceRepr {
- ptr: *const u8,
- len: &'static u8,
-}
-
-union SliceTransmute {
- repr: SliceRepr,
- bad: BadSliceRepr,
- slice: &'static [u8],
- str: &'static str,
- my_str: &'static MyStr,
- my_slice: &'static MySliceBool,
-}
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-struct DynRepr {
- ptr: *const u8,
- vtable: *const u8,
-}
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-struct DynRepr2 {
- ptr: *const u8,
- vtable: *const u64,
-}
-
-#[repr(C)]
-#[derive(Copy, Clone)]
-struct BadDynRepr {
- ptr: *const u8,
- vtable: usize,
-}
-
-union DynTransmute {
- repr: DynRepr,
- repr2: DynRepr2,
- bad: BadDynRepr,
- rust: &'static Trait,
-}
-
-trait Trait {}
-impl Trait for bool {}
-
-// custom unsized type
-struct MyStr(str);
-
-// custom unsized type with sized fields
-struct MySlice<T: ?Sized>(bool, T);
-type MySliceBool = MySlice<[bool]>;
-
-// OK
-const A: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.str};
-// bad str
-const B: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str};
-//~^ ERROR this constant likely exhibits undefined behavior
-// bad str
-const C: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str};
-//~^ ERROR this constant likely exhibits undefined behavior
-// bad str in user-defined unsized type
-const C2: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str};
-//~^ ERROR this constant likely exhibits undefined behavior
-
-// OK
-const A2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 1 } }.slice};
-// bad slice
-const B2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice};
-//~^ ERROR this constant likely exhibits undefined behavior
-// bad slice
-const C3: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice};
-//~^ ERROR this constant likely exhibits undefined behavior
-
-// bad trait object
-const D: &Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust};
-//~^ ERROR this constant likely exhibits undefined behavior
-// bad trait object
-const E: &Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust};
-//~^ ERROR this constant likely exhibits undefined behavior
-// bad trait object
-const F: &Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust};
-//~^ ERROR this constant likely exhibits undefined behavior
-
-// bad data *inside* the trait object
-const G: &Trait = &unsafe { BoolTransmute { val: 3 }.bl };
-//~^ ERROR this constant likely exhibits undefined behavior
-// bad data *inside* the slice
-const H: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }];
-//~^ ERROR this constant likely exhibits undefined behavior
-
-// good MySliceBool
-const I1: &MySliceBool = &MySlice(true, [false]);
-// bad: sized field is not okay
-const I2: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]);
-//~^ ERROR this constant likely exhibits undefined behavior
-// bad: unsized part is not okay
-const I3: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]);
-//~^ ERROR this constant likely exhibits undefined behavior
-
-// invalid UTF-8
-const J1: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str };
-//~^ ERROR this constant likely exhibits undefined behavior
-// invalid UTF-8 in user-defined str-like
-const J2: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str };
-//~^ ERROR this constant likely exhibits undefined behavior
-
-fn main() {
-}
+++ /dev/null
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:87:1
- |
-LL | const B: &str = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.str};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or out-of-bounds memory at .<deref>
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:90:1
- |
-LL | const C: &str = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.str};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:93:1
- |
-LL | const C2: &MyStr = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.my_str};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:99:1
- |
-LL | const B2: &[u8] = unsafe { SliceTransmute { repr: SliceRepr { ptr: &42, len: 999 } }.slice};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized or out-of-bounds memory at .<deref>[1]
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:102:1
- |
-LL | const C3: &[u8] = unsafe { SliceTransmute { bad: BadSliceRepr { ptr: &42, len: &3 } }.slice};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-integer slice length in fat pointer
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:106:1
- |
-LL | const D: &Trait = unsafe { DynTransmute { repr: DynRepr { ptr: &92, vtable: &3 } }.rust};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid vtable in fat pointer at .<deref>
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:109:1
- |
-LL | const E: &Trait = unsafe { DynTransmute { repr2: DynRepr2 { ptr: &92, vtable: &3 } }.rust};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid vtable in fat pointer at .<deref>
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:112:1
- |
-LL | const F: &Trait = unsafe { DynTransmute { bad: BadDynRepr { ptr: &92, vtable: 3 } }.rust};
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-pointer vtable in fat pointer
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:116:1
- |
-LL | const G: &Trait = &unsafe { BoolTransmute { val: 3 }.bl };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>, but expected something in the range 0..=1
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:119:1
- |
-LL | const H: &[bool] = &[unsafe { BoolTransmute { val: 3 }.bl }];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>[0], but expected something in the range 0..=1
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:125:1
- |
-LL | const I2: &MySliceBool = &MySlice(unsafe { BoolTransmute { val: 3 }.bl }, [false]);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.0, but expected something in the range 0..=1
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:128:1
- |
-LL | const I3: &MySliceBool = &MySlice(true, [unsafe { BoolTransmute { val: 3 }.bl }]);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 3 at .<deref>.1[0], but expected something in the range 0..=1
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:132:1
- |
-LL | const J1: &str = unsafe { SliceTransmute { slice: &[0xFF] }.str };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-UTF-8 data in str at .<deref>
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error[E0080]: this constant likely exhibits undefined behavior
- --> $DIR/union-ub-fat-ptr.rs:135:1
- |
-LL | const J2: &MyStr = unsafe { SliceTransmute { slice: &[0xFF] }.my_str };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered non-UTF-8 data in str at .<deref>.0
- |
- = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rust compiler repository if you believe it should not be considered undefined behavior
-
-error: aborting due to 14 previous errors
-
-For more information about this error, try `rustc --explain E0080`.
/// Version of LLDB
pub lldb_version: Option<String>,
+ /// Whether LLDB has native rust support
+ pub lldb_native_rust: bool,
+
/// Version of LLVM
pub llvm_version: Option<String>,
// Ignore if actual version is smaller the minimum required
// version
lldb_version_to_int(actual_version) < lldb_version_to_int(min_version)
+ } else if line.starts_with("rust-lldb") && !config.lldb_native_rust {
+ true
} else {
false
}
let android_cross_path = opt_path(matches, "android-cross-path");
let (gdb, gdb_version, gdb_native_rust) = analyze_gdb(matches.opt_str("gdb"), &target,
&android_cross_path);
+ let (lldb_version, lldb_native_rust) = extract_lldb_version(matches.opt_str("lldb-version"));
let color = match matches.opt_str("color").as_ref().map(|x| &**x) {
Some("auto") | None => ColorConfig::AutoColor,
gdb,
gdb_version,
gdb_native_rust,
- lldb_version: extract_lldb_version(matches.opt_str("lldb-version")),
+ lldb_version,
+ lldb_native_rust,
llvm_version: matches.opt_str("llvm-version"),
system_llvm: matches.opt_present("system-llvm"),
android_cross_path: android_cross_path,
None
}
-fn extract_lldb_version(full_version_line: Option<String>) -> Option<String> {
+/// Returns (LLDB version, LLDB is rust-enabled)
+fn extract_lldb_version(full_version_line: Option<String>) -> (Option<String>, bool) {
// Extract the major LLDB version from the given version string.
// LLDB version strings are different for Apple and non-Apple platforms.
- // At the moment, this function only supports the Apple variant, which looks
- // like this:
+ // The Apple variant looks like this:
//
// LLDB-179.5 (older versions)
// lldb-300.2.51 (new versions)
//
// We are only interested in the major version number, so this function
// will return `Some("179")` and `Some("300")` respectively.
+ //
+ // Upstream versions look like:
+ // lldb version 6.0.1
+ //
+ // There doesn't seem to be a way to correlate the Apple version
+ // with the upstream version, and since the tests were originally
+ // written against Apple versions, we make a fake Apple version by
+ // multiplying the first number by 100. This is a hack, but
+ // normally fine because the only non-Apple version we test is
+ // rust-enabled.
if let Some(ref full_version_line) = full_version_line {
if !full_version_line.trim().is_empty() {
.take_while(|c| c.is_digit(10))
.collect::<String>();
if !vers.is_empty() {
- return Some(vers);
+ return (Some(vers), full_version_line.contains("rust-enabled"));
+ }
+ }
+
+ if full_version_line.starts_with("lldb version ") {
+ let vers = full_version_line[13..]
+ .chars()
+ .take_while(|c| c.is_digit(10))
+ .collect::<String>();
+ if !vers.is_empty() {
+ return (Some(vers + "00"), full_version_line.contains("rust-enabled"));
}
}
}
}
- None
+ (None, false)
}
fn is_blacklisted_lldb_version(version: &str) -> bool {
}
}
+ let prefixes = if self.config.lldb_native_rust {
+ static PREFIXES: &'static [&'static str] = &["lldb", "lldbr"];
+ println!("NOTE: compiletest thinks it is using LLDB with native rust support");
+ PREFIXES
+ } else {
+ static PREFIXES: &'static [&'static str] = &["lldb", "lldbg"];
+ println!("NOTE: compiletest thinks it is using LLDB without native rust support");
+ PREFIXES
+ };
+
// Parse debugger commands etc from test files
let DebuggerCommands {
commands,
check_lines,
breakpoint_lines,
..
- } = self.parse_debugger_commands(&["lldb"]);
+ } = self.parse_debugger_commands(prefixes);
// Write debugger script:
// We don't want to hang when calling `quit` while the process is still running
-Subproject commit e8f6973e2d40ab39e30cdbe0cf8e77a72c867d4f
+Subproject commit cc275c63a90d4bea394e76607b2e10611eb1be36