fn visit_address_of()

in checker/src/block_visitor.rs [1778:1922]


    fn visit_address_of(&mut self, path: Rc<Path>, place: &mir::Place<'tcx>) {
        let target_type = self
            .type_visitor()
            .get_path_rustc_type(&path, self.bv.current_span);
        let source_type = self
            .type_visitor()
            .get_rustc_place_type(place, self.bv.current_span);
        let value_path = self.visit_lh_place(place);
        match (source_type.kind(), target_type.kind()) {
            (TyKind::Ref(_, st, _), TyKind::Ref(_, tt, _)) if st.eq(tt) => {
                // If we are just changing the mutability or lifetime of the reference,
                // the value stays the same for us.
                let value = self
                    .bv
                    .lookup_path_and_refine_result(value_path, source_type);
                self.bv.update_value_at(path, value);
                return;
            }
            _ => {}
        }
        let value = match &value_path.value {
            PathEnum::QualifiedPath {
                qualifier,
                selector,
                ..
            } if *selector.as_ref() == PathSelector::Deref => {
                if source_type.is_box() {
                    // A Box contains a Unique (transparently wrapped) pointer to the thing in the box.
                    // &*box means get hold of the unwrapped pointer.
                    // box.0 gives us a path to the Unique wrapper.
                    // box.0.0 gives us a path to the unwrapped pointer.
                    // qualifier has already been modified to be box.0.0 during path construction.

                    if !self.type_visitor().is_slice_pointer(target_type.kind()) {
                        // The unwrapped pointer is the thing to store at path.
                        let ptr_val = self
                            .bv
                            .lookup_path_and_refine_result(qualifier.clone(), target_type);
                        self.bv.update_value_at(path, ptr_val);
                    } else {
                        // The target type is a slice pointer, so the thing inside the box must be
                        // an array slice (or a string). In the heap model, the contents of a box
                        // is always stored in a heap block and the value at path box.0.0 is a
                        // reference to that heap block. We use that reference as the thin
                        // part of the target slice pointer and we assume that the length
                        // has been stored at path box.0.1. The latter is an artifact of the heap
                        // model and there is actually no such field in the Unique struct.
                        //
                        // To look up box.0.0 we need the type of the thin pointer, which we
                        // derive from target_type (which is known to be a slice pointer).
                        let deref_ty = self.type_visitor().get_dereferenced_type(target_type);
                        let thin_ptr_ty = self.bv.tcx.mk_ptr(rustc_middle::ty::TypeAndMut {
                            ty: deref_ty,
                            mutbl: rustc_hir::Mutability::Not,
                        });
                        let ptr_val = self
                            .bv
                            .lookup_path_and_refine_result(qualifier.clone(), thin_ptr_ty);
                        // Since path is the location of slice pointer, path.0 is the location of
                        // the thin pointer part of it.
                        self.bv
                            .update_value_at(Path::new_field(path.clone(), 0), ptr_val);

                        // box.0.1 is written to with the slice length when the box is initialized
                        // with the slice value.
                        if let PathEnum::QualifiedPath {
                            qualifier: wrapper_path,
                            ..
                        } = &qualifier.value
                        {
                            let len_val = self.bv.lookup_path_and_refine_result(
                                Path::new_length(wrapper_path.clone()),
                                self.bv.tcx.types.usize,
                            );
                            // path.1 is the length part of the target slice pointer
                            self.bv
                                .update_value_at(Path::new_length(path.clone()), len_val);
                        } else {
                            assume_unreachable!("qualifier should be box.0.0  {:?}", qualifier);
                        }
                    }
                    return;
                }
                // If q does not point to a Box, then we have:
                // r = *q copies the value that q points to.
                // r = &*q copies q.
                // The reason for this distinction seems to be that there is no need for yet another
                // way to get a pointer to a copy of the thing p points to (i.e. we already have &r
                // when r = *q), whereas it is useful to have a way to change the nature of p.
                // For example we see things like r = &mut *p.
                // Effectively, thus, we are transmuting the pointer.

                let mut qualifier = qualifier;
                if matches!(source_type.kind(), TyKind::Slice(..) | TyKind::Str) {
                    if let PathEnum::QualifiedPath {
                        qualifier: q,
                        selector,
                        ..
                    } = &qualifier.value
                    {
                        if **selector == PathSelector::Field(0) {
                            qualifier = q;
                        } else {
                            assume_unreachable!(
                                "*q where q is a slice pointer should become *(q.0)"
                            );
                        }
                    } else {
                        assume_unreachable!("*q where q is a slice pointer should become *(q.0)");
                    }
                }
                let source_pointer_ty = self
                    .type_visitor()
                    .get_path_rustc_type(qualifier, self.bv.current_span);
                let source_pointer_path = qualifier.canonicalize(&self.bv.current_environment);
                self.bv.copy_and_transmute(
                    source_pointer_path,
                    source_pointer_ty,
                    path,
                    target_type,
                );
                return;
            }
            PathEnum::Computed { .. }
            | PathEnum::Offset { .. }
            | PathEnum::QualifiedPath { .. } => {
                AbstractValue::make_reference(value_path.canonicalize(&self.bv.current_environment))
            }
            PathEnum::PromotedConstant { .. } => {
                if let Some(val) = self.bv.current_environment.value_at(&value_path) {
                    if let Expression::HeapBlock { .. } = &val.expression {
                        let heap_path = Path::new_heap_block(val.clone());
                        AbstractValue::make_reference(heap_path)
                    } else {
                        AbstractValue::make_reference(value_path.clone())
                    }
                } else {
                    AbstractValue::make_reference(value_path.clone())
                }
            }
            PathEnum::HeapBlock { value } => value.clone(),
            _ => AbstractValue::make_reference(value_path.clone()),
        };
        self.bv.update_value_at(path, value);
    }