rustc_codegen_ssa/mir/
locals.rs

1//! Locals are in a private module as updating `LocalRef::Operand` has to
2//! be careful wrt to subtyping. To deal with this we only allow updates by using
3//! `FunctionCx::overwrite_local` which handles it automatically.
4
5use std::ops::{Index, IndexMut};
6
7use rustc_index::IndexVec;
8use rustc_middle::mir;
9use rustc_middle::ty::print::with_no_trimmed_paths;
10use tracing::{debug, warn};
11
12use crate::mir::{FunctionCx, LocalRef};
13use crate::traits::BuilderMethods;
14
15pub(super) struct Locals<'tcx, V> {
16    values: IndexVec<mir::Local, LocalRef<'tcx, V>>,
17}
18
19impl<'tcx, V> Index<mir::Local> for Locals<'tcx, V> {
20    type Output = LocalRef<'tcx, V>;
21    #[inline]
22    fn index(&self, index: mir::Local) -> &LocalRef<'tcx, V> {
23        &self.values[index]
24    }
25}
26
27/// To mutate locals, use `FunctionCx::overwrite_local` instead.
28impl<'tcx, V, Idx: ?Sized> !IndexMut<Idx> for Locals<'tcx, V> {}
29
30impl<'tcx, V> Locals<'tcx, V> {
31    pub(super) fn empty() -> Locals<'tcx, V> {
32        Locals { values: IndexVec::default() }
33    }
34
35    pub(super) fn indices(&self) -> impl DoubleEndedIterator<Item = mir::Local> + Clone + 'tcx {
36        self.values.indices()
37    }
38}
39
40impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
41    pub(super) fn initialize_locals(&mut self, values: Vec<LocalRef<'tcx, Bx::Value>>) {
42        assert!(self.locals.values.is_empty());
43        // FIXME(#115215): After #115025 get's merged this might not be necessary
44        for (local, value) in values.into_iter().enumerate() {
45            match value {
46                LocalRef::Place(_) | LocalRef::UnsizedPlace(_) | LocalRef::PendingOperand => (),
47                LocalRef::Operand(op) => {
48                    let local = mir::Local::from_usize(local);
49                    let expected_ty = self.monomorphize(self.mir.local_decls[local].ty);
50                    if expected_ty != op.layout.ty {
51                        warn!(
52                            "Unexpected initial operand type:\nexpected {expected_ty:?},\nfound    {:?}.\n\
53                            See <https://github.com/rust-lang/rust/issues/114858>.",
54                            op.layout.ty
55                        );
56                    }
57                }
58            }
59            self.locals.values.push(value);
60        }
61    }
62
63    pub(super) fn overwrite_local(
64        &mut self,
65        local: mir::Local,
66        mut value: LocalRef<'tcx, Bx::Value>,
67    ) {
68        match value {
69            LocalRef::Place(_) | LocalRef::UnsizedPlace(_) | LocalRef::PendingOperand => (),
70            LocalRef::Operand(ref mut op) => {
71                let local_ty = self.monomorphize(self.mir.local_decls[local].ty);
72                if local_ty != op.layout.ty {
73                    // FIXME(#112651): This can be changed to an ICE afterwards.
74                    debug!("updating type of operand due to subtyping");
75                    with_no_trimmed_paths!(debug!(?op.layout.ty));
76                    with_no_trimmed_paths!(debug!(?local_ty));
77                    op.layout.ty = local_ty;
78                }
79            }
80        };
81
82        self.locals.values[local] = value;
83    }
84}