Skip to main content

rustc_mir_build/builder/
cfg.rs

1//! Routines for manipulating the control-flow graph.
2
3use rustc_data_structures::thin_vec::ThinVec;
4use rustc_middle::mir::*;
5use rustc_middle::ty::TyCtxt;
6use tracing::debug;
7
8use crate::builder::CFG;
9
10impl<'tcx> CFG<'tcx> {
11    pub(crate) fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> {
12        &self.basic_blocks[blk]
13    }
14
15    pub(crate) fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<'tcx> {
16        &mut self.basic_blocks[blk]
17    }
18
19    // llvm.org/PR32488 makes this function use an excess of stack space. Mark
20    // it as #[inline(never)] to keep rustc's stack use in check.
21    #[inline(never)]
22    pub(crate) fn start_new_block(&mut self) -> BasicBlock {
23        self.basic_blocks.push(BasicBlockData::new(None, false))
24    }
25
26    pub(crate) fn start_new_cleanup_block(&mut self) -> BasicBlock {
27        let bb = self.start_new_block();
28        self.block_data_mut(bb).is_cleanup = true;
29        bb
30    }
31
32    pub(crate) fn push(&mut self, block: BasicBlock, statement: Statement<'tcx>) {
33        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_mir_build/src/builder/cfg.rs:33",
                        "rustc_mir_build::builder::cfg", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_build/src/builder/cfg.rs"),
                        ::tracing_core::__macro_support::Option::Some(33u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_build::builder::cfg"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("push({0:?}, {1:?})",
                                                    block, statement) as &dyn Value))])
            });
    } else { ; }
};debug!("push({:?}, {:?})", block, statement);
34        self.block_data_mut(block).statements.push(statement);
35    }
36
37    pub(crate) fn push_assign(
38        &mut self,
39        block: BasicBlock,
40        source_info: SourceInfo,
41        place: Place<'tcx>,
42        rvalue: Rvalue<'tcx>,
43    ) {
44        self.push(
45            block,
46            Statement::new(source_info, StatementKind::Assign(Box::new((place, rvalue)))),
47        );
48    }
49
50    pub(crate) fn push_assign_constant(
51        &mut self,
52        block: BasicBlock,
53        source_info: SourceInfo,
54        temp: Place<'tcx>,
55        constant: ConstOperand<'tcx>,
56    ) {
57        self.push_assign(
58            block,
59            source_info,
60            temp,
61            Rvalue::Use(Operand::Constant(Box::new(constant)), WithRetag::Yes),
62        );
63    }
64
65    pub(crate) fn push_assign_unit(
66        &mut self,
67        block: BasicBlock,
68        source_info: SourceInfo,
69        place: Place<'tcx>,
70        tcx: TyCtxt<'tcx>,
71    ) {
72        self.push_assign(
73            block,
74            source_info,
75            place,
76            Rvalue::Use(
77                Operand::Constant(Box::new(ConstOperand {
78                    span: source_info.span,
79                    user_ty: None,
80                    const_: Const::zero_sized(tcx.types.unit),
81                })),
82                WithRetag::Yes,
83            ),
84        );
85    }
86
87    pub(crate) fn push_fake_read(
88        &mut self,
89        block: BasicBlock,
90        source_info: SourceInfo,
91        cause: FakeReadCause,
92        place: Place<'tcx>,
93    ) {
94        let kind = StatementKind::FakeRead(Box::new((cause, place)));
95        let stmt = Statement::new(source_info, kind);
96        self.push(block, stmt);
97    }
98
99    pub(crate) fn push_place_mention(
100        &mut self,
101        block: BasicBlock,
102        source_info: SourceInfo,
103        place: Place<'tcx>,
104    ) {
105        let kind = StatementKind::PlaceMention(Box::new(place));
106        let stmt = Statement::new(source_info, kind);
107        self.push(block, stmt);
108    }
109
110    /// Adds a dummy statement whose only role is to associate a span with its
111    /// enclosing block for the purposes of coverage instrumentation.
112    ///
113    /// This results in more accurate coverage reports for certain kinds of
114    /// syntax (e.g. `continue` or `if !`) that would otherwise not appear in MIR.
115    pub(crate) fn push_coverage_span_marker(&mut self, block: BasicBlock, source_info: SourceInfo) {
116        let kind = StatementKind::Coverage(coverage::CoverageKind::SpanMarker);
117        let stmt = Statement::new(source_info, kind);
118        self.push(block, stmt);
119    }
120
121    pub(crate) fn terminate(
122        &mut self,
123        block: BasicBlock,
124        source_info: SourceInfo,
125        kind: TerminatorKind<'tcx>,
126    ) -> &mut Terminator<'tcx> {
127        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_mir_build/src/builder/cfg.rs:127",
                        "rustc_mir_build::builder::cfg", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_mir_build/src/builder/cfg.rs"),
                        ::tracing_core::__macro_support::Option::Some(127u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_mir_build::builder::cfg"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("terminating block {0:?} <- {1:?}",
                                                    block, kind) as &dyn Value))])
            });
    } else { ; }
};debug!("terminating block {:?} <- {:?}", block, kind);
128        if true {
    if !self.block_data(block).terminator.is_none() {
        {
            ::core::panicking::panic_fmt(format_args!("terminate: block {0:?}={1:?} already has a terminator set",
                    block, self.block_data(block)));
        }
    };
};debug_assert!(
129            self.block_data(block).terminator.is_none(),
130            "terminate: block {:?}={:?} already has a terminator set",
131            block,
132            self.block_data(block)
133        );
134        self.block_data_mut(block).terminator =
135            Some(Terminator { source_info, kind, attributes: ThinVec::new() });
136        self.block_data_mut(block).terminator.as_mut().unwrap()
137    }
138
139    /// In the `origin` block, push a `goto -> target` terminator.
140    pub(crate) fn goto(
141        &mut self,
142        origin: BasicBlock,
143        source_info: SourceInfo,
144        target: BasicBlock,
145    ) -> &mut Terminator<'tcx> {
146        self.terminate(origin, source_info, TerminatorKind::Goto { target })
147    }
148}