Skip to main content

rustc_mir_build/builder/
cfg.rs

1//! Routines for manipulating the control-flow graph.
2
3use rustc_middle::mir::*;
4use rustc_middle::ty::TyCtxt;
5use tracing::debug;
6
7use crate::builder::CFG;
8
9impl<'tcx> CFG<'tcx> {
10    pub(crate) fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> {
11        &self.basic_blocks[blk]
12    }
13
14    pub(crate) fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<'tcx> {
15        &mut self.basic_blocks[blk]
16    }
17
18    // llvm.org/PR32488 makes this function use an excess of stack space. Mark
19    // it as #[inline(never)] to keep rustc's stack use in check.
20    #[inline(never)]
21    pub(crate) fn start_new_block(&mut self) -> BasicBlock {
22        self.basic_blocks.push(BasicBlockData::new(None, false))
23    }
24
25    pub(crate) fn start_new_cleanup_block(&mut self) -> BasicBlock {
26        let bb = self.start_new_block();
27        self.block_data_mut(bb).is_cleanup = true;
28        bb
29    }
30
31    pub(crate) fn push(&mut self, block: BasicBlock, statement: Statement<'tcx>) {
32        {
    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:32",
                        "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(32u32),
                        ::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);
33        self.block_data_mut(block).statements.push(statement);
34    }
35
36    pub(crate) fn push_assign(
37        &mut self,
38        block: BasicBlock,
39        source_info: SourceInfo,
40        place: Place<'tcx>,
41        rvalue: Rvalue<'tcx>,
42    ) {
43        self.push(
44            block,
45            Statement::new(source_info, StatementKind::Assign(Box::new((place, rvalue)))),
46        );
47    }
48
49    pub(crate) fn push_assign_constant(
50        &mut self,
51        block: BasicBlock,
52        source_info: SourceInfo,
53        temp: Place<'tcx>,
54        constant: ConstOperand<'tcx>,
55    ) {
56        self.push_assign(
57            block,
58            source_info,
59            temp,
60            Rvalue::Use(Operand::Constant(Box::new(constant))),
61        );
62    }
63
64    pub(crate) fn push_assign_unit(
65        &mut self,
66        block: BasicBlock,
67        source_info: SourceInfo,
68        place: Place<'tcx>,
69        tcx: TyCtxt<'tcx>,
70    ) {
71        self.push_assign(
72            block,
73            source_info,
74            place,
75            Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
76                span: source_info.span,
77                user_ty: None,
78                const_: Const::zero_sized(tcx.types.unit),
79            }))),
80        );
81    }
82
83    pub(crate) fn push_fake_read(
84        &mut self,
85        block: BasicBlock,
86        source_info: SourceInfo,
87        cause: FakeReadCause,
88        place: Place<'tcx>,
89    ) {
90        let kind = StatementKind::FakeRead(Box::new((cause, place)));
91        let stmt = Statement::new(source_info, kind);
92        self.push(block, stmt);
93    }
94
95    pub(crate) fn push_place_mention(
96        &mut self,
97        block: BasicBlock,
98        source_info: SourceInfo,
99        place: Place<'tcx>,
100    ) {
101        let kind = StatementKind::PlaceMention(Box::new(place));
102        let stmt = Statement::new(source_info, kind);
103        self.push(block, stmt);
104    }
105
106    /// Adds a dummy statement whose only role is to associate a span with its
107    /// enclosing block for the purposes of coverage instrumentation.
108    ///
109    /// This results in more accurate coverage reports for certain kinds of
110    /// syntax (e.g. `continue` or `if !`) that would otherwise not appear in MIR.
111    pub(crate) fn push_coverage_span_marker(&mut self, block: BasicBlock, source_info: SourceInfo) {
112        let kind = StatementKind::Coverage(coverage::CoverageKind::SpanMarker);
113        let stmt = Statement::new(source_info, kind);
114        self.push(block, stmt);
115    }
116
117    pub(crate) fn terminate(
118        &mut self,
119        block: BasicBlock,
120        source_info: SourceInfo,
121        kind: TerminatorKind<'tcx>,
122    ) {
123        {
    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:123",
                        "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(123u32),
                        ::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);
124        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!(
125            self.block_data(block).terminator.is_none(),
126            "terminate: block {:?}={:?} already has a terminator set",
127            block,
128            self.block_data(block)
129        );
130        self.block_data_mut(block).terminator = Some(Terminator { source_info, kind });
131    }
132
133    /// In the `origin` block, push a `goto -> target` terminator.
134    pub(crate) fn goto(&mut self, origin: BasicBlock, source_info: SourceInfo, target: BasicBlock) {
135        self.terminate(origin, source_info, TerminatorKind::Goto { target })
136    }
137}