Skip to content

Commit 4232276

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

File tree

3 files changed

+114
-7
lines changed

3 files changed

+114
-7
lines changed

compiler/stable_mir/src/mir/body.rs

Lines changed: 19 additions & 1 deletion
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

Lines changed: 5 additions & 1 deletion
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

Lines changed: 90 additions & 5 deletions
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)