Skip to content

Commit 12054dc

Browse files
committed
miri: validity visitor comments and path printing improvements
1 parent dc92ad4 commit 12054dc

File tree

3 files changed

+47
-24
lines changed

3 files changed

+47
-24
lines changed

src/librustc_mir/interpret/validity.rs

+45-22
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,12 @@ pub enum PathElem {
6767
Field(Symbol),
6868
Variant(Symbol),
6969
GeneratorState(VariantIdx),
70-
ClosureVar(Symbol),
70+
CapturedVar(Symbol),
7171
ArrayElem(usize),
7272
TupleElem(usize),
7373
Deref,
74-
Tag,
74+
EnumTag,
75+
GeneratorTag,
7576
DynDowncast,
7677
}
7778

@@ -109,17 +110,18 @@ fn write_path(out: &mut String, path: &Vec<PathElem>) {
109110
for elem in path.iter() {
110111
match elem {
111112
Field(name) => write!(out, ".{}", name),
112-
Variant(name) => write!(out, ".<downcast-variant({})>", name),
113+
EnumTag => write!(out, ".<enum-tag>"),
114+
Variant(name) => write!(out, ".<enum-variant({})>", name),
115+
GeneratorTag => write!(out, ".<generator-tag>"),
113116
GeneratorState(idx) => write!(out, ".<generator-state({})>", idx.index()),
114-
ClosureVar(name) => write!(out, ".<closure-var({})>", name),
117+
CapturedVar(name) => write!(out, ".<captured-var({})>", name),
115118
TupleElem(idx) => write!(out, ".{}", idx),
116119
ArrayElem(idx) => write!(out, "[{}]", idx),
117120
// `.<deref>` does not match Rust syntax, but it is more readable for long paths -- and
118121
// some of the other items here also are not Rust syntax. Actually we can't
119122
// even use the usual syntax because we are just showing the projections,
120123
// not the root.
121124
Deref => write!(out, ".<deref>"),
122-
Tag => write!(out, ".<enum-tag>"),
123125
DynDowncast => write!(out, ".<dyn-downcast>"),
124126
}
125127
.unwrap()
@@ -170,6 +172,21 @@ struct ValidityVisitor<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> {
170172

171173
impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M> {
172174
fn aggregate_field_path_elem(&mut self, layout: TyLayout<'tcx>, field: usize) -> PathElem {
175+
// First, check if we are projecting to a variant.
176+
match layout.variants {
177+
layout::Variants::Multiple { discr_index, .. } => {
178+
if discr_index == field {
179+
return match layout.ty.kind {
180+
ty::Adt(def, ..) if def.is_enum() => PathElem::EnumTag,
181+
ty::Generator(..) => PathElem::GeneratorTag,
182+
_ => bug!("non-variant type {:?}", layout.ty),
183+
};
184+
}
185+
}
186+
layout::Variants::Single { .. } => {}
187+
}
188+
189+
// Now we know we are projecting to a field, so figure out which one.
173190
match layout.ty.kind {
174191
// generators and closures.
175192
ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
@@ -190,7 +207,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
190207
}
191208
}
192209

193-
PathElem::ClosureVar(name.unwrap_or_else(|| {
210+
PathElem::CapturedVar(name.unwrap_or_else(|| {
194211
// Fall back to showing the field index.
195212
sym::integer(field)
196213
}))
@@ -207,10 +224,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
207224
// Inside a variant
208225
PathElem::Field(def.variants[index].fields[field].ident.name)
209226
}
210-
layout::Variants::Multiple { discr_index, .. } => {
211-
assert_eq!(discr_index, field);
212-
PathElem::Tag
213-
}
227+
layout::Variants::Multiple { .. } => bug!("we handled variants above"),
214228
}
215229
}
216230

@@ -441,11 +455,12 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
441455
fn visit_scalar(
442456
&mut self,
443457
op: OpTy<'tcx, M::PointerTag>,
444-
layout: &layout::Scalar,
458+
scalar_layout: &layout::Scalar,
445459
) -> InterpResult<'tcx> {
446460
let value = self.ecx.read_scalar(op)?;
461+
let valid_range = &scalar_layout.valid_range;
462+
let (lo, hi) = valid_range.clone().into_inner();
447463
// Determine the allowed range
448-
let (lo, hi) = layout.valid_range.clone().into_inner();
449464
// `max_hi` is as big as the size fits
450465
let max_hi = u128::max_value() >> (128 - op.layout.size.bits());
451466
assert!(hi <= max_hi);
@@ -459,7 +474,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
459474
value.not_undef(),
460475
value,
461476
self.path,
462-
format_args!("something {}", wrapping_range_format(&layout.valid_range, max_hi),)
477+
format_args!("something {}", wrapping_range_format(valid_range, max_hi),)
463478
);
464479
let bits = match value.to_bits_or_ptr(op.layout.size, self.ecx) {
465480
Err(ptr) => {
@@ -471,7 +486,7 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
471486
self.path,
472487
format_args!(
473488
"something that cannot possibly fail to be {}",
474-
wrapping_range_format(&layout.valid_range, max_hi)
489+
wrapping_range_format(valid_range, max_hi)
475490
)
476491
)
477492
}
@@ -484,21 +499,21 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M
484499
self.path,
485500
format_args!(
486501
"something that cannot possibly fail to be {}",
487-
wrapping_range_format(&layout.valid_range, max_hi)
502+
wrapping_range_format(valid_range, max_hi)
488503
)
489504
)
490505
}
491506
}
492507
Ok(data) => data,
493508
};
494509
// Now compare. This is slightly subtle because this is a special "wrap-around" range.
495-
if wrapping_range_contains(&layout.valid_range, bits) {
510+
if wrapping_range_contains(&valid_range, bits) {
496511
Ok(())
497512
} else {
498513
throw_validation_failure!(
499514
bits,
500515
self.path,
501-
format_args!("something {}", wrapping_range_format(&layout.valid_range, max_hi))
516+
format_args!("something {}", wrapping_range_format(valid_range, max_hi))
502517
)
503518
}
504519
}
@@ -594,7 +609,8 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
594609

595610
// *After* all of this, check the ABI. We need to check the ABI to handle
596611
// types like `NonNull` where the `Scalar` info is more restrictive than what
597-
// the fields say. But in most cases, this will just propagate what the fields say,
612+
// the fields say (`rustc_layout_scalar_valid_range_start`).
613+
// But in most cases, this will just propagate what the fields say,
598614
// and then we want the error to point at the field -- so, first recurse,
599615
// then check ABI.
600616
//
@@ -603,11 +619,18 @@ impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
603619
// MyNewtype and then the scalar in there).
604620
match op.layout.abi {
605621
layout::Abi::Uninhabited => unreachable!(), // checked above
606-
layout::Abi::Scalar(ref layout) => {
607-
self.visit_scalar(op, layout)?;
622+
layout::Abi::Scalar(ref scalar_layout) => {
623+
self.visit_scalar(op, scalar_layout)?;
624+
}
625+
layout::Abi::ScalarPair { .. } | layout::Abi::Vector { .. } => {
626+
// These have fields that we already visited above, so we already checked
627+
// all their scalar-level restrictions.
628+
// There is also no equivalent to `rustc_layout_scalar_valid_range_start`
629+
// that would make skipping them here an issue.
630+
}
631+
layout::Abi::Aggregate { .. } => {
632+
// Nothing to do.
608633
}
609-
// FIXME: Should we do something for ScalarPair? Vector?
610-
_ => {}
611634
}
612635

613636
Ok(())

src/test/ui/consts/const-eval/ub-enum.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ error[E0080]: it is undefined behavior to use this value
6666
--> $DIR/ub-enum.rs:71:1
6767
|
6868
LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { TransmuteChar { a: !0 }.b }));
69-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at .<downcast-variant(Some)>.0.1, but expected a valid unicode codepoint
69+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 4294967295 at .<enum-variant(Some)>.0.1, but expected a valid unicode codepoint
7070
|
7171
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
7272

src/test/ui/consts/const-eval/ub-upvars.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ LL | | let bad_ref: &'static u16 = unsafe { mem::transmute(0usize) };
66
LL | | let another_var = 13;
77
LL | | move || { let _ = bad_ref; let _ = another_var; }
88
LL | | };
9-
| |__^ type validation failed: encountered a NULL reference at .<deref>.<dyn-downcast>.<closure-var(bad_ref)>
9+
| |__^ type validation failed: encountered a NULL reference at .<deref>.<dyn-downcast>.<captured-var(bad_ref)>
1010
|
1111
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
1212

0 commit comments

Comments
 (0)