in checker/src/body_visitor.rs [908:1057]
fn promote_reference(
&mut self,
environment: &mut Environment,
result_rustc_type: Ty<'tcx>,
promoted_root: &Rc<Path>,
local_path: &Rc<Path>,
) {
let target_type = self.type_visitor().get_dereferenced_type(result_rustc_type);
if target_type.is_unit() {
return;
}
if ExpressionType::from(target_type.kind()).is_primitive() {
// Kind of weird, but seems to be generated for debugging support.
// Move the value into a path, so that we can drop the reference to the soon to be dead local.
let target_value = self
.exit_environment
.as_ref()
.unwrap()
.value_map
.get(local_path)
.unwrap_or_else(|| {
panic!(
"expect reference target to have a value {:?} in env {:?}",
local_path, self.exit_environment
)
});
let value_path = Path::get_as_path(target_value.clone());
let promoted_value = AbstractValue::make_from(Expression::Reference(value_path), 1);
environment.strong_update_value_at(promoted_root.clone(), promoted_value);
} else if let TyKind::Ref(_, t, _) = target_type.kind() {
// Promoting a reference to a reference.
let eight: Rc<AbstractValue> = self.get_u128_const_val(8);
let (_, heap_root) = self.get_new_heap_block(eight.clone(), eight, false, target_type);
let layout_path = Path::new_layout(heap_root.clone());
let layout_value = self
.current_environment
.value_at(&layout_path)
.expect("new heap block should have a layout");
environment.strong_update_value_at(layout_path, layout_value.clone());
let exit_env_map = self.exit_environment.as_ref().unwrap().value_map.clone();
if !exit_env_map.contains_key(local_path) {
self.promote_reference(
environment,
*t,
&Path::new_field(heap_root.clone(), 0),
&Path::new_field(local_path.clone(), 0),
);
self.promote_reference(
environment,
self.tcx.types.usize,
&Path::new_length(heap_root),
&Path::new_length(local_path.clone()),
);
} else {
let target_value = exit_env_map
.get(local_path)
.expect("expect reference target to have a value");
environment.strong_update_value_at(heap_root.clone(), target_value.clone());
if let Expression::Reference(path) = &target_value.expression {
match &path.value {
PathEnum::LocalVariable { .. } => {
self.promote_reference(environment, target_type, &heap_root, path)
}
PathEnum::Computed { value } => {
environment.strong_update_value_at(path.clone(), value.clone());
if target_type.is_slice() {
let len_path = Path::new_length(path.clone());
if let Some(len_val) = exit_env_map.get(&len_path) {
environment.strong_update_value_at(len_path, len_val.clone());
}
}
}
_ => {}
}
}
let promoted_value = AbstractValue::make_from(Expression::Reference(heap_root), 1);
environment.strong_update_value_at(promoted_root.clone(), promoted_value);
}
} else if let TyKind::Str = target_type.kind() {
// Promoting a string constant
let exit_env_map = &self.exit_environment.as_ref().unwrap().value_map;
let target_value = exit_env_map
.get(local_path)
.expect("expect reference target to have a value");
environment.strong_update_value_at(promoted_root.clone(), target_value.clone());
if let Expression::Reference(str_path) = &target_value.expression {
if let PathEnum::Computed { value } = &str_path.value {
environment.strong_update_value_at(str_path.clone(), value.clone());
let len_path = Path::new_length(str_path.clone());
if let Some(len_val) = exit_env_map.get(&len_path) {
environment.strong_update_value_at(len_path, len_val.clone());
}
}
}
} else {
// A composite value needs to get to get promoted to the heap
// in order to propagate it via function summaries.
let byte_size = self.type_visitor().get_type_size(target_type);
let byte_size_value = self.get_u128_const_val(byte_size as u128);
let elem_size = self
.type_visitor()
.get_type_size(self.type_visitor().get_element_type(target_type));
let alignment: Rc<AbstractValue> = Rc::new(
(match elem_size {
0 => 1,
1 | 2 | 4 | 8 => elem_size,
_ => 8,
} as u128)
.into(),
);
let (_, heap_root) =
self.get_new_heap_block(byte_size_value, alignment, false, target_type);
let layout_path = Path::new_layout(heap_root.clone());
let layout_value = self
.current_environment
.value_at(&layout_path)
.expect("new heap block should have a layout");
environment.strong_update_value_at(layout_path, layout_value.clone());
for (path, value) in self
.exit_environment
.as_ref()
.unwrap()
.value_map
.iter()
.filter(|(p, _)| (*p) == local_path || p.is_rooted_by(local_path))
{
let renamed_path = path.replace_root(local_path, heap_root.clone());
environment.strong_update_value_at(renamed_path, value.clone());
}
let thin_pointer_to_heap = AbstractValue::make_reference(heap_root);
if self.type_visitor().is_slice_pointer(target_type.kind()) {
let promoted_thin_pointer_path = Path::new_field(promoted_root.clone(), 0);
environment
.strong_update_value_at(promoted_thin_pointer_path, thin_pointer_to_heap);
let length_value = self
.exit_environment
.as_ref()
.unwrap()
.value_map
.get(&Path::new_length(local_path.clone()))
.unwrap_or_else(|| assume_unreachable!("promoted constant slice source is expected to have a length value, see source at {:?}", self.current_span))
.clone();
let length_path = Path::new_length(promoted_root.clone());
environment.strong_update_value_at(length_path, length_value);
} else {
environment.strong_update_value_at(promoted_root.clone(), thin_pointer_to_heap);
}
}
}