Skip to content

Commit 0a0e7e6

Browse files
committed
Add tests to allocation methods and fix is_null()
1 parent 9cb6463 commit 0a0e7e6

File tree

3 files changed

+114
-7
lines changed

3 files changed

+114
-7
lines changed

compiler/stable_mir/src/mir/body.rs

+19-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub struct Body {
2121
pub(super) arg_count: usize,
2222

2323
/// Debug information pertaining to user variables, including captures.
24-
pub(super) var_debug_info: Vec<VarDebugInfo>,
24+
pub var_debug_info: Vec<VarDebugInfo>,
2525
}
2626

2727
pub type BasicBlockIdx = usize;
@@ -616,6 +616,24 @@ pub struct VarDebugInfo {
616616
pub argument_index: Option<u16>,
617617
}
618618

619+
impl VarDebugInfo {
620+
/// Return a local variable if this info is related to one.
621+
pub fn local(&self) -> Option<Local> {
622+
match &self.value {
623+
VarDebugInfoContents::Place(place) if place.projection.is_empty() => Some(place.local),
624+
VarDebugInfoContents::Place(_) | VarDebugInfoContents::Const(_) => None,
625+
}
626+
}
627+
628+
/// Return a constant if this info is related to one.
629+
pub fn constant(&self) -> Option<&ConstOperand> {
630+
match &self.value {
631+
VarDebugInfoContents::Place(_) => None,
632+
VarDebugInfoContents::Const(const_op) => Some(const_op),
633+
}
634+
}
635+
}
636+
619637
pub type SourceScope = u32;
620638

621639
#[derive(Clone, Debug, Eq, PartialEq)]

compiler/stable_mir/src/ty.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -901,6 +901,7 @@ impl Allocation {
901901
read_target_uint(&raw)
902902
}
903903

904+
/// Read this allocation and try to convert it to an unassigned integer.
904905
pub fn read_uint(&self) -> Result<u128, Error> {
905906
if self.bytes.len() > 16 {
906907
return Err(error!("Allocation is bigger than largest integer"));
@@ -909,6 +910,7 @@ impl Allocation {
909910
read_target_uint(&raw)
910911
}
911912

913+
/// Read this allocation and try to convert it to a signed integer.
912914
pub fn read_int(&self) -> Result<i128, Error> {
913915
if self.bytes.len() > 16 {
914916
return Err(error!("Allocation is bigger than largest integer"));
@@ -917,6 +919,7 @@ impl Allocation {
917919
read_target_int(&raw)
918920
}
919921

922+
/// Read this allocation and try to convert it to a boolean.
920923
pub fn read_bool(&self) -> Result<bool, Error> {
921924
match self.read_int()? {
922925
0 => Ok(false),
@@ -925,13 +928,14 @@ impl Allocation {
925928
}
926929
}
927930

931+
/// Read this allocation as a pointer and return whether it represents a `null` pointer.
928932
pub fn is_null(&self) -> Result<bool, Error> {
929933
let len = self.bytes.len();
930934
let ptr_len = MachineInfo::target_pointer_width().bytes();
931935
if len != ptr_len {
932936
return Err(error!("Expected width of pointer (`{ptr_len}`), but found: `{len}`"));
933937
}
934-
Ok(self.read_uint()? == 0)
938+
Ok(self.read_uint()? == 0 && self.provenance.ptrs.is_empty())
935939
}
936940
}
937941

tests/ui-fulldeps/stable-mir/check_allocation.rs

+90-5
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,16 @@ extern crate stable_mir;
2323

2424
use rustc_middle::ty::TyCtxt;
2525
use rustc_smir::rustc_internal;
26-
use stable_mir::{CrateItem, CrateItems, ItemKind};
2726
use stable_mir::crate_def::CrateDef;
2827
use stable_mir::mir::alloc::GlobalAlloc;
29-
use stable_mir::mir::mono::StaticDef;
28+
use stable_mir::mir::mono::{Instance, StaticDef};
29+
use stable_mir::mir::Body;
30+
use stable_mir::ty::{Allocation, ConstantKind};
31+
use stable_mir::{CrateItem, CrateItems, ItemKind};
3032
use std::ascii::Char;
3133
use std::assert_matches::assert_matches;
34+
use std::cmp::{max, min};
35+
use std::collections::HashMap;
3236
use std::io::Write;
3337
use std::ops::ControlFlow;
3438

@@ -41,6 +45,7 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
4145
check_foo(*get_item(&items, (ItemKind::Static, "FOO")).unwrap());
4246
check_bar(*get_item(&items, (ItemKind::Static, "BAR")).unwrap());
4347
check_len(*get_item(&items, (ItemKind::Static, "LEN")).unwrap());
48+
check_other_consts(*get_item(&items, (ItemKind::Fn, "other_consts")).unwrap());
4449
ControlFlow::Continue(())
4550
}
4651

@@ -80,6 +85,73 @@ fn check_bar(item: CrateItem) {
8085
assert_eq!(std::str::from_utf8(&allocation.raw_bytes().unwrap()), Ok("Bar"));
8186
}
8287

88+
/// Check the allocation data for constants used in `other_consts` function.
89+
fn check_other_consts(item: CrateItem) {
90+
// Instance body will force constant evaluation.
91+
let body = Instance::try_from(item).unwrap().body().unwrap();
92+
let assigns = collect_consts(&body);
93+
assert_eq!(assigns.len(), 9);
94+
for (name, alloc) in assigns {
95+
match name.as_str() {
96+
"_max_u128" => {
97+
assert_eq!(alloc.read_uint(), Ok(u128::MAX), "Failed parsing allocation: {alloc:?}")
98+
}
99+
"_min_i128" => {
100+
assert_eq!(alloc.read_int(), Ok(i128::MIN), "Failed parsing allocation: {alloc:?}")
101+
}
102+
"_max_i8" => {
103+
assert_eq!(
104+
alloc.read_int().unwrap() as i8,
105+
i8::MAX,
106+
"Failed parsing allocation: {alloc:?}"
107+
)
108+
}
109+
"_char" => {
110+
assert_eq!(
111+
char::from_u32(alloc.read_uint().unwrap() as u32),
112+
Some('x'),
113+
"Failed parsing allocation: {alloc:?}"
114+
)
115+
}
116+
"_false" => {
117+
assert_eq!(alloc.read_bool(), Ok(false), "Failed parsing allocation: {alloc:?}")
118+
}
119+
"_true" => {
120+
assert_eq!(alloc.read_bool(), Ok(true), "Failed parsing allocation: {alloc:?}")
121+
}
122+
"_ptr" => {
123+
assert_eq!(alloc.is_null(), Ok(false), "Failed parsing allocation: {alloc:?}")
124+
}
125+
"_null_ptr" => {
126+
assert_eq!(alloc.is_null(), Ok(true), "Failed parsing allocation: {alloc:?}")
127+
}
128+
"_tuple" => {
129+
// The order of fields is not guaranteed.
130+
let first = alloc.read_partial_uint(0..4).unwrap();
131+
let second = alloc.read_partial_uint(4..8).unwrap();
132+
assert_eq!(max(first, second) as u32, u32::MAX);
133+
assert_eq!(min(first, second), 10);
134+
}
135+
_ => {
136+
unreachable!("{name} -- {alloc:?}")
137+
}
138+
}
139+
}
140+
}
141+
142+
/// Collects all the constant assignments.
143+
pub fn collect_consts(body: &Body) -> HashMap<String, &Allocation> {
144+
body.var_debug_info
145+
.iter()
146+
.filter_map(|info| {
147+
info.constant().map(|const_op| {
148+
let ConstantKind::Allocated(alloc) = const_op.const_.kind() else { unreachable!() };
149+
(info.name.clone(), alloc)
150+
})
151+
})
152+
.collect::<HashMap<_, _>>()
153+
}
154+
83155
/// Check the allocation data for `LEN`.
84156
///
85157
/// ```no_run
@@ -97,9 +169,7 @@ fn get_item<'a>(
97169
items: &'a CrateItems,
98170
item: (ItemKind, &str),
99171
) -> Option<&'a stable_mir::CrateItem> {
100-
items.iter().find(|crate_item| {
101-
(item.0 == crate_item.kind()) && crate_item.name() == item.1
102-
})
172+
items.iter().find(|crate_item| (item.0 == crate_item.kind()) && crate_item.name() == item.1)
103173
}
104174

105175
/// This test will generate and analyze a dummy crate using the stable mir.
@@ -126,10 +196,25 @@ fn generate_input(path: &str) -> std::io::Result<()> {
126196
static LEN: usize = 2;
127197
static FOO: [&str; 2] = ["hi", "there"];
128198
static BAR: &str = "Bar";
199+
const NULL: *const u8 = std::ptr::null();
200+
const TUPLE: (u32, u32) = (10, u32::MAX);
201+
202+
fn other_consts() {{
203+
let _max_u128 = u128::MAX;
204+
let _min_i128 = i128::MIN;
205+
let _max_i8 = i8::MAX;
206+
let _char = 'x';
207+
let _false = false;
208+
let _true = true;
209+
let _ptr = &BAR;
210+
let _null_ptr: *const u8 = NULL;
211+
let _tuple = TUPLE;
212+
}}
129213
130214
pub fn main() {{
131215
println!("{{FOO:?}}! {{BAR}}");
132216
assert_eq!(FOO.len(), LEN);
217+
other_consts();
133218
}}"#
134219
)?;
135220
Ok(())

0 commit comments

Comments
 (0)