Skip to content

Commit 8488d00

Browse files
committed
Add tests to allocation methods and fix is_null()
1 parent f0a1c8e commit 8488d00

File tree

3 files changed

+104
-7
lines changed

3 files changed

+104
-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;
@@ -527,6 +527,24 @@ pub struct VarDebugInfo {
527527
pub argument_index: Option<u16>,
528528
}
529529

530+
impl VarDebugInfo {
531+
/// Return a local variable if this info is related to one.
532+
pub fn local(&self) -> Option<Local> {
533+
match &self.value {
534+
VarDebugInfoContents::Place(place) if place.projection.is_empty() => Some(place.local),
535+
VarDebugInfoContents::Place(_) | VarDebugInfoContents::Const(_) => None,
536+
}
537+
}
538+
539+
/// Return a constant if this info is related to one.
540+
pub fn constant(&self) -> Option<&ConstOperand> {
541+
match &self.value {
542+
VarDebugInfoContents::Place(_) => None,
543+
VarDebugInfoContents::Const(const_op) => Some(const_op),
544+
}
545+
}
546+
}
547+
530548
pub type SourceScope = u32;
531549

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

compiler/stable_mir/src/ty.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,7 @@ impl Allocation {
840840
read_target_uint(&raw)
841841
}
842842

843+
/// Read this allocation and try to convert it to an unassigned integer.
843844
pub fn read_uint(&self) -> Result<u128, Error> {
844845
if self.bytes.len() > 16 {
845846
return Err(error!("Allocation is bigger than largest integer"));
@@ -848,6 +849,7 @@ impl Allocation {
848849
read_target_uint(&raw)
849850
}
850851

852+
/// Read this allocation and try to convert it to a signed integer.
851853
pub fn read_int(&self) -> Result<i128, Error> {
852854
if self.bytes.len() > 16 {
853855
return Err(error!("Allocation is bigger than largest integer"));
@@ -856,6 +858,7 @@ impl Allocation {
856858
read_target_int(&raw)
857859
}
858860

861+
/// Read this allocation and try to convert it to a boolean.
859862
pub fn read_bool(&self) -> Result<bool, Error> {
860863
match self.read_int()? {
861864
0 => Ok(false),
@@ -864,13 +867,14 @@ impl Allocation {
864867
}
865868
}
866869

870+
/// Read this allocation as a pointer and return whether it represents a `null` pointer.
867871
pub fn is_null(&self) -> Result<bool, Error> {
868872
let len = self.bytes.len();
869873
let ptr_len = MachineInfo::target_pointer_width().bytes();
870874
if len != ptr_len {
871875
return Err(error!("Expected width of pointer (`{ptr_len}`), but found: `{len}`"));
872876
}
873-
Ok(self.read_uint()? == 0)
877+
Ok(self.read_uint()? == 0 && self.provenance.ptrs.is_empty())
874878
}
875879
}
876880

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

+80-5
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,15 @@ 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::collections::HashMap;
3235
use std::io::Write;
3336
use std::ops::ControlFlow;
3437

@@ -41,6 +44,7 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
4144
check_foo(*get_item(&items, (ItemKind::Static, "FOO")).unwrap());
4245
check_bar(*get_item(&items, (ItemKind::Static, "BAR")).unwrap());
4346
check_len(*get_item(&items, (ItemKind::Static, "LEN")).unwrap());
47+
check_other_consts(*get_item(&items, (ItemKind::Fn, "other_consts")).unwrap());
4448
ControlFlow::Continue(())
4549
}
4650

@@ -80,6 +84,66 @@ fn check_bar(item: CrateItem) {
8084
assert_eq!(std::str::from_utf8(&allocation.raw_bytes().unwrap()), Ok("Bar"));
8185
}
8286

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

105167
/// This test will generate and analyze a dummy crate using the stable mir.
@@ -126,10 +188,23 @@ fn generate_input(path: &str) -> std::io::Result<()> {
126188
static LEN: usize = 2;
127189
static FOO: [&str; 2] = ["hi", "there"];
128190
static BAR: &str = "Bar";
191+
const NULL: *const u8 = std::ptr::null();
192+
193+
fn other_consts() {{
194+
let _max_u128 = u128::MAX;
195+
let _min_i128 = i128::MIN;
196+
let _max_i8 = i8::MAX;
197+
let _char = 'x';
198+
let _false = false;
199+
let _true = true;
200+
let _ptr = &BAR;
201+
let _null_ptr: *const u8 = NULL;
202+
}}
129203
130204
pub fn main() {{
131205
println!("{{FOO:?}}! {{BAR}}");
132206
assert_eq!(FOO.len(), LEN);
207+
other_consts();
133208
}}"#
134209
)?;
135210
Ok(())

0 commit comments

Comments
 (0)