diff --git a/charon/Cargo.lock b/charon/Cargo.lock index 4ca55861d..df10f3570 100644 --- a/charon/Cargo.lock +++ b/charon/Cargo.lock @@ -255,6 +255,7 @@ dependencies = [ "serde-map-to-array", "serde_json", "serde_stacker", + "smallvec", "snapbox", "stacker", "strip-ansi-escapes", diff --git a/charon/Cargo.toml b/charon/Cargo.toml index 2a31ec4a7..902a2c24f 100644 --- a/charon/Cargo.toml +++ b/charon/Cargo.toml @@ -69,6 +69,7 @@ serde_json = { version = "1.0.91", features = ["unbounded_depth"] } serde-map-to-array = { version = "1.1.1", features = ["std"] } serde_stacker = "0.1.11" serde = { version = "1.0.152", features = ["derive", "rc"] } +smallvec = "1.15.1" stacker = "0.1" strip-ansi-escapes = "0.2.1" take_mut = "0.2.2" diff --git a/charon/src/transform/control_flow/ullbc_to_llbc.rs b/charon/src/transform/control_flow/ullbc_to_llbc.rs index 33c1fffd7..b67101b02 100644 --- a/charon/src/transform/control_flow/ullbc_to_llbc.rs +++ b/charon/src/transform/control_flow/ullbc_to_llbc.rs @@ -1,38 +1,16 @@ //! ULLBC to LLBC //! -//! We reconstruct the control-flow in the Unstructured LLBC. -//! -//! The reconstruction algorithm is not written to be efficient (its complexity -//! is probably very bad), but it was not written to be: this is still an early -//! stage and we want the algorithm to generate the best reconstruction as -//! possible. We still need to test the algorithm on more interesting examples, -//! and will consider making it more efficient once it is a bit mature and well -//! tested. -//! Also note that we more importantly focus on making the algorithm sound: the -//! reconstructed program must always be equivalent to the original MIR program, -//! and the fact that the reconstruction preserves this property must be obvious. -//! -//! Finally, we conjecture the execution time shouldn't be too much a problem: -//! we don't expect the translation mechanism to be applied on super huge functions -//! (which will be difficult to formally analyze), and the MIR graphs are actually -//! not that big because statements are grouped into code blocks (a block is made -//! of a list of statements, followed by a terminator - branchings and jumps can -//! only be performed by terminators -, meaning that MIR graphs don't have that -//! many nodes and edges). - +//! Reconstruct the control-flow of the ULLBC function bodies. Based on the algorithm from "Beyond +//! Relooper" (https://dl.acm.org/doi/10.1145/3547621). use indexmap::IndexMap; use itertools::Itertools; -use num_bigint::BigInt; -use num_rational::BigRational; use petgraph::algo::dominators::simple_fast; -use petgraph::algo::toposort; use petgraph::graphmap::DiGraphMap; use petgraph::visit::{DfsPostOrder, Walker}; -use std::collections::{BTreeSet, HashMap, HashSet, VecDeque}; -use std::u32; +use smallvec::SmallVec; +use std::mem; use crate::common::ensure_sufficient_stack; -use crate::errors::sanity_check; use crate::formatter::IntoFormatter; use crate::llbc_ast as tgt; use crate::meta::{Span, combine_span}; @@ -42,1682 +20,418 @@ use crate::transform::ctx::TransformPass; use crate::ullbc_ast::{self as src, BlockId}; use crate::{ast::*, register_error}; +fn translate_statement(st: &src::Statement) -> tgt::Statement { + let kind = match st.kind.clone() { + src::StatementKind::Assign(place, rvalue) => tgt::StatementKind::Assign(place, rvalue), + src::StatementKind::SetDiscriminant(place, variant_id) => { + tgt::StatementKind::SetDiscriminant(place, variant_id) + } + src::StatementKind::CopyNonOverlapping(copy) => { + tgt::StatementKind::CopyNonOverlapping(copy) + } + src::StatementKind::StorageLive(var_id) => tgt::StatementKind::StorageLive(var_id), + src::StatementKind::StorageDead(var_id) => tgt::StatementKind::StorageDead(var_id), + src::StatementKind::Deinit(place) => tgt::StatementKind::Deinit(place), + src::StatementKind::Assert(assert) => tgt::StatementKind::Assert(assert), + src::StatementKind::Nop => tgt::StatementKind::Nop, + src::StatementKind::Error(s) => tgt::StatementKind::Error(s), + }; + tgt::Statement::new(st.span, kind) +} + +/// Block id that must be handled specifically when jumping to it. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum SpecialJump { + // Continue to the head of the loop. + Loop, + // Break forward. + JumpForward, + // Do nothing, the desired block is already the next one. + Fallthrough, +} + /// Control-Flow Graph type Cfg = DiGraphMap; -/// Small utility -struct BlockInfo<'a> { - cfg: &'a CfgInfo, - body: &'a src::ExprBody, - exits_info: &'a ExitInfo, - explored: &'a mut HashSet, +/// Cfg data about a block. +struct BlockCfgData<'a> { + contents: &'a src::BlockData, + /// Whether this node is reachable from the root. + reachable: bool, + /// The (unique) entrypoints of each loop. Unique because we error on irreducible cfgs. + is_loop_header: bool, + /// Blocks that have multiple incoming control-flow edges. + is_merge_target: bool, + /// Blocks that have incoming control-flow edges that require forward jumps, i.e. can't simply + /// be translated as the exit to a `switch` node. + is_nontrivial_merge_target: bool, + /// Reverse postorder numbering of the blocks. Using `u32` is fine because we already limit + /// `BlockId`s to `u32::MAX`. If the node is not reachable, the id is `u32::MAX` and should not + /// be used. + reverse_postorder_id: u32, + /// Block that immediately dominates this one. `None` for the root an unreachable nodes. + dominator: Option, + /// Nodes that this block immediately dominates. Sorted by reverse_postorder_id, with largest + /// id first. + immediately_dominates: SmallVec<[BlockId; 2]>, + /// Like `immediately_dominates`, but restricted to nodes that are merge targets. + immediately_dominated_merge_targets: SmallVec<[BlockId; 2]>, } -/// This structure contains various information about a function's CFG. -#[derive(Debug)] -struct CfgInfo { - /// The CFG - pub cfg: Cfg, - /// The CFG where all the backward edges have been removed - pub cfg_no_be: Cfg, - /// We consider the destination of the backward edges to be loop entries and - /// store them here. - pub loop_entries: HashSet, - /// The backward edges - pub backward_edges: HashSet<(src::BlockId, src::BlockId)>, - /// The blocks whose terminators are a switch are stored here. - pub switch_blocks: HashSet, - /// The set of nodes from where we can only reach error nodes (panic, etc.) - pub only_reach_error: HashSet, +struct ReloopCtx<'a> { + /// The control-flow graph. + cfg: Cfg, + /// Cfg data for each block. + block_data: Vector>, + /// Locals for the target body, so that we can add intermediate variables. + locals: Locals, + /// Stack of block ids we can't just recursively translate in the current context. + /// A useful invariant is that the block at the top of the stack is the block where + /// control-flow will continue naturally at the end of the current block. Therefore this stack + /// also works as a list of blocks left to translate after the current one. + special_jump_stack: Vec<(BlockId, SpecialJump)>, } /// Error indicating that the control-flow graph is not reducible. The contained block id is a /// block involved in an irreducible subgraph. struct Irreducible(BlockId); -/// Build the CFGs (the "regular" CFG and the CFG without backward edges) and -/// compute some information like the loop entries and the switch blocks. -fn build_cfg_info(body: &src::ExprBody) -> Result { - let start_block = BlockId::ZERO; +impl<'a> ReloopCtx<'a> { + fn new(src_body: &'a src::ExprBody, start_block: BlockId) -> Result { + let mut block_data = src_body.body.map_ref(|contents| BlockCfgData { + contents, + reverse_postorder_id: u32::MAX, + reachable: false, + is_loop_header: false, + is_merge_target: false, + is_nontrivial_merge_target: false, + dominator: None, + immediately_dominates: SmallVec::default(), + immediately_dominated_merge_targets: SmallVec::default(), + }); - // Build the node graph (we ignore unwind paths for now). - let mut cfg = Cfg::new(); - for (block_id, block) in body.body.iter_indexed() { - cfg.add_node(block_id); - for tgt in block.targets_ignoring_unwind() { - cfg.add_edge(block_id, tgt, ()); + // Build the node graph (we ignore unwind paths for now). + let mut cfg = Cfg::new(); + for (block_id, block) in src_body.body.iter_indexed() { + cfg.add_node(block_id); + for tgt in block.targets_ignoring_unwind() { + cfg.add_edge(block_id, tgt, ()); + } } - } - // Compute the dominator tree. - let dominator_tree = simple_fast(&cfg, start_block); + // Compute the dominator tree and reverse postorder numbering. + let dominator_tree = simple_fast(&cfg, start_block); + for (i, block_id) in DfsPostOrder::new(&cfg, start_block).iter(&cfg).enumerate() { + block_data[block_id].reachable = true; - // Compute reverse postorder numbering. - let mut reverse_postorder = body.body.map_ref_opt(|_| None); - for (i, block_id) in DfsPostOrder::new(&cfg, start_block).iter(&cfg).enumerate() { - let rev_post_id = reverse_postorder.slot_count() - i; - assert!(rev_post_id <= u32::MAX as usize); - reverse_postorder.set_slot(block_id, rev_post_id as u32); - } + let rev_post_id: usize = block_data.slot_count() - i; + block_data[block_id].reverse_postorder_id = rev_post_id.try_into().unwrap(); - // Compute the forward graph (without backward edges). - let mut cfg_no_be = Cfg::new(); - let mut loop_entries = HashSet::new(); - let mut backward_edges = HashSet::new(); - let mut switch_blocks = HashSet::new(); - for src in cfg.nodes() { - if reverse_postorder.get(src).is_none() { - // Unreachable block - continue; - } - cfg_no_be.add_node(src); - if body.body[src].terminator.kind.is_switch() { - switch_blocks.insert(src); - } - for tgt in cfg.neighbors(src) { - // Check if the edge is a backward edge. - if reverse_postorder[src] >= reverse_postorder[tgt] { - // This is a backward edge - loop_entries.insert(tgt); - backward_edges.insert((src, tgt)); - // A cfg is reducible iff the target of every back edge dominates the - // edge's source. - if !dominator_tree.dominators(src).unwrap().contains(&tgt) { - return Err(Irreducible(src)); - } - } else { - cfg_no_be.add_edge(src, tgt, ()); + // Store the dominator tree in `block_data`. + if let Some(dominator) = dominator_tree.immediate_dominator(block_id) { + block_data[block_id].dominator = Some(dominator); + block_data[dominator].immediately_dominates.push(block_id); } - } - } - // Compute the nodes that can only reach error nodes. - let mut only_reach_error = HashSet::new(); - for block_id in DfsPostOrder::new(&cfg_no_be, start_block).iter(&cfg_no_be) { - let block = &body.body[block_id]; - // The node can only reach error nodes if: - // - it is an error node; - // - or it has neighbors and they all lead to errors. - // Note that if there is a backward edge, `only_reach_error` cannot contain this - // node yet. In other words, this does not consider infinite loops as reaching an - // error node. - let targets = cfg.neighbors(block_id).collect_vec(); - if block.terminator.is_error() - || (!targets.is_empty() && targets.iter().all(|tgt| only_reach_error.contains(tgt))) - { - only_reach_error.insert(block_id); + // Detect merge targets. + if cfg + .neighbors_directed(block_id, petgraph::Direction::Incoming) + .count() + >= 2 + { + block_data[block_id].is_merge_target = true; + } } - } - - Ok(CfgInfo { - cfg, - cfg_no_be, - loop_entries, - backward_edges, - switch_blocks, - only_reach_error, - }) -} -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -struct BlockWithRank { - /// A "rank" quantity that we use to order the nodes. - /// By placing the `rank` field before the `id`, we make sure that - /// we use the rank first in the lexicographic order. - rank: T, - id: src::BlockId, -} - -type OrdBlockId = BlockWithRank; - -/// For the rank we use: -/// - a "flow" quantity (see [BlocksInfo]) -/// - the *inverse* rank in the topological sort (i.e., `- topo_rank`) -type FlowBlockId = BlockWithRank<(BigRational, isize)>; - -#[derive(Debug, Clone)] -struct LoopExitCandidateInfo { - /// The occurrences going to this exit. - /// For every occurrence, we register the distance between the loop entry - /// and the node from which the edge going to the exit starts. - /// If later we have to choose between candidates with the same number - /// of occurrences, we choose the one with the smallest distances. - /// - /// Note that it *may* happen that we have several exit candidates referenced - /// more than once for one loop. This comes from the fact that whenever we - /// reach a node from which the loop entry is not reachable (without using a - /// backward edge leading to an outer loop entry), we register this node - /// as well as all its children as exit candidates. - /// Consider the following example: - /// ```text - /// while i < max { - /// if cond { - /// break; - /// } - /// s += i; - /// i += 1 - /// } - /// // All the below nodes are exit candidates (each of them is referenced twice) - /// s += 1; - /// return s; - /// ``` - pub occurrences: Vec, -} - -/// Check if a loop entry is reachable from a node, in a graph where we remove -/// the backward edges going directly to the loop entry. -/// -/// If the loop entry is not reachable, it means that: -/// - the loop entry is not reachable at all -/// - or it is only reachable through an outer loop -/// -/// The starting node should be a (transitive) child of the loop entry. -/// We use this to find candidates for loop exits. -fn loop_entry_is_reachable_from_inner( - cfg: &CfgInfo, - loop_entry: src::BlockId, - block_id: src::BlockId, -) -> bool { - // It is reachable in the complete graph. Check if it is reachable by not - // going through backward edges which go to outer loops. In practice, we - // just need to forbid the use of any backward edges at the exception of - // those which go directly to the current loop's entry. This means that we - // ignore backward edges to outer loops of course, but also backward edges - // to inner loops because we shouldn't need to follow those (there should be - // more direct paths). + // Fill in the remaining data. + for src in cfg.nodes() { + if !block_data[src].reachable { + continue; + } - // Explore the graph starting at block_id - let mut explored: HashSet = HashSet::new(); - let mut stack: VecDeque = VecDeque::new(); - stack.push_back(block_id); - while !stack.is_empty() { - let bid = stack.pop_front().unwrap(); - if explored.contains(&bid) { - continue; - } - explored.insert(bid); + // Sort by postorder id. We have to `mem::take` to avoid borrowck issues. + let mut dominatees = mem::take(&mut block_data[src].immediately_dominates); + dominatees.sort_by_key(|&child| block_data[child].reverse_postorder_id); + dominatees.reverse(); + block_data[src].immediately_dominates = dominatees; + block_data[src].immediately_dominated_merge_targets = block_data[src] + .immediately_dominates + .iter() + .copied() + .filter(|&child| block_data[child].is_merge_target) + .collect(); - for next_id in cfg.cfg.neighbors(bid) { - // Check if this is a backward edge - if cfg.backward_edges.contains(&(bid, next_id)) { - // Backward edge: only allow those going directly to the current - // loop's entry - if next_id == loop_entry { - // The loop entry is reachable - return true; - } else { - // Forbidden edge: ignore - continue; + // Detect loops. + for tgt in cfg.neighbors(src) { + // Check if the edge is a backward edge. + if block_data[src].reverse_postorder_id >= block_data[tgt].reverse_postorder_id { + // This is a backward edge + block_data[tgt].is_loop_header = true; + // A cfg is reducible iff the target of every back edge dominates the edge's + // source. + if !dominator_tree.dominators(src).unwrap().contains(&tgt) { + return Err(Irreducible(src)); + } } - } else { - // Nothing special: add the node to the stack for further - // exploration - stack.push_back(next_id); } } - } - - // The loop entry is not reachable - false -} -struct FilteredLoopParents { - remaining_parents: Vec<(src::BlockId, usize)>, - removed_parents: Vec<(src::BlockId, usize)>, -} - -fn filter_loop_parents( - cfg: &CfgInfo, - parent_loops: &Vec<(src::BlockId, usize)>, - block_id: src::BlockId, -) -> Option { - let mut eliminate: usize = 0; - for (loop_id, _ldist) in parent_loops.iter().rev() { - if !loop_entry_is_reachable_from_inner(cfg, *loop_id, block_id) { - eliminate += 1; - } else { - break; - } - } - - if eliminate > 0 { - // Split the vector of parents - let (remaining_parents, removed_parents) = - parent_loops.split_at(parent_loops.len() - eliminate); - let (mut remaining_parents, removed_parents) = - (remaining_parents.to_vec(), removed_parents.to_vec()); - - // Update the distance to the last loop - we just increment the distance - // by 1, because from the point of view of the parent loop, we just exited - // a block and go to the next sequence of instructions. - if !remaining_parents.is_empty() { - remaining_parents.last_mut().unwrap().1 += 1; - } - - Some(FilteredLoopParents { - remaining_parents, - removed_parents, + Ok(ReloopCtx { + cfg, + block_data, + locals: src_body.locals.clone(), + special_jump_stack: Vec::new(), }) - } else { - None } -} - -/// List the nodes reachable from a starting point. -/// We list the nodes and the depth (in the AST) at which they were found. -fn list_reachable(cfg: &Cfg, start: src::BlockId) -> HashMap { - let mut reachable: HashMap = HashMap::new(); - let mut stack: VecDeque<(src::BlockId, usize)> = VecDeque::new(); - stack.push_back((start, 0)); - while !stack.is_empty() { - let (bid, dist) = stack.pop_front().unwrap(); - - // Ignore this node if we already registered it with a better distance - match reachable.get(&bid) { - None => (), - Some(original_dist) => { - if *original_dist < dist { - continue; - } - } + /// We traverse the dominator tree just like `reloop_block`, keeping track of which block will + /// be executed next after this one. We use this to detect merge blocks that don't need forward + /// jumps, i.e. that can be implemented as simple `switch` blocks. This must match the form of + /// `reloop_block` to be correct. + fn detect_trivial_merges(&mut self, bid: BlockId, mut next: Option) { + if self.block_data[bid].is_loop_header { + next = Some(bid); } - // Inset the node with its distance - reachable.insert(bid, dist); - - // Add the children to the stack - for child in cfg.neighbors(bid) { - stack.push_back((child, dist + 1)); + for child in self.block_data[bid] + .immediately_dominated_merge_targets + .clone() + { + self.detect_trivial_merges(child, next); + next = Some(child); } - } - - // Return - reachable -} - -/// Register a node and its children as exit candidates for a list of -/// parent loops. -fn register_children_as_loop_exit_candidates( - cfg: &CfgInfo, - loop_exits: &mut HashMap>, - removed_parent_loops: &Vec<(src::BlockId, usize)>, - block_id: src::BlockId, -) { - // List the reachable nodes - let reachable = list_reachable(&cfg.cfg_no_be, block_id); - - let mut base_dist = 0; - // For every parent loop, in reverse order (we go from last to first in - // order to correctly compute the distances) - for (loop_id, loop_dist) in removed_parent_loops.iter().rev() { - // Update the distance to the loop entry - base_dist += *loop_dist; - - // Retrieve the candidates - let candidates = loop_exits.get_mut(loop_id).unwrap(); - // Update them - for (bid, dist) in reachable.iter() { - let distance = base_dist + *dist; - match candidates.get_mut(bid) { - None => { - candidates.insert( - *bid, - LoopExitCandidateInfo { - occurrences: vec![distance], - }, - ); - } - Some(c) => { - c.occurrences.push(distance); - } + for tgt in self.cfg.neighbors(bid).collect_vec() { + if next != Some(tgt) { + self.block_data[tgt].is_nontrivial_merge_target = true; + } + if tgt != bid && !self.block_data[tgt].is_merge_target { + self.detect_trivial_merges(tgt, next) } } } -} -/// Compute the loop exit candidates. -/// -/// There may be several candidates with the same "optimality" (same number of -/// occurrences, etc.), in which case we choose the first one which was registered -/// (the order in which we explore the graph is deterministic): this is why we -/// store the candidates in a linked hash map. -fn compute_loop_exit_candidates( - cfg: &CfgInfo, - explored: &mut HashSet, - ordered_loops: &mut Vec, - loop_exits: &mut HashMap>, - // List of parent loops, with the distance to the entry of the loop (the distance - // is the distance between the current node and the loop entry for the last parent, - // and the distance between the parents for the others). - mut parent_loops: Vec<(src::BlockId, usize)>, - block_id: src::BlockId, -) { - if explored.contains(&block_id) { - return; + /// Translate this block and all the blocks it dominates, recursively over the dominator tree. + /// We follow the algorithm in the paper. + fn reloop_block(&mut self, bid: BlockId) -> tgt::Block { + ensure_sufficient_stack(|| self.reloop_block_inner(bid)) } - explored.insert(block_id); - - // Check if we enter a loop - add the corresponding node if necessary - if cfg.loop_entries.contains(&block_id) { - parent_loops.push((block_id, 1)); - ordered_loops.push(block_id); - } else { - // Increase the distance with the parent loop - if !parent_loops.is_empty() { - parent_loops.last_mut().unwrap().1 += 1; + fn reloop_block_inner(&mut self, bid: BlockId) -> tgt::Block { + // Some of the blocks we might jump to inside this tree can't be translated as normal + // blocks: the loop backward edges must become `continue`s and the merge nodes may need + // some care if we're jumping to them from distant locations. + // For this purpose, we push to the `context_stack` the block ids that must be translated + // spoecially. In `translate_jump` we check the stack. + let old_context_depth = self.special_jump_stack.len(); + + // Catch jumps to the loop header. + if self.block_data[bid].is_loop_header { + self.special_jump_stack.push((bid, SpecialJump::Loop)); + } + + // Catch jumps to a merge node. The merge nodes are translated after this node, and we can + // jump to them using `break`. The child with highest postorder numbering is nested + // outermost in this scheme. + let merge_children = &self.block_data[bid].immediately_dominated_merge_targets; + for &child in merge_children { + let jump = if self.block_data[child].is_nontrivial_merge_target { + SpecialJump::JumpForward + } else { + SpecialJump::Fallthrough + }; + self.special_jump_stack.push((child, jump)); } - }; - // Retrieve the children - note that we ignore the back edges - let children = cfg.cfg_no_be.neighbors(block_id); - for child in children { - // If the parent loop entry is not reachable from the child without going - // through a backward edge which goes directly to the loop entry, consider - // this node a potential exit. - ensure_sufficient_stack(|| { - match filter_loop_parents(cfg, &parent_loops, child) { - None => { - compute_loop_exit_candidates( - cfg, - explored, - ordered_loops, - loop_exits, - parent_loops.clone(), - child, - ); - } - Some(fparent_loops) => { - // We filtered some parent loops: it means this child and its - // children are loop exit candidates for all those loops: we must - // thus register them. - // Note that we register the child *and* its children: the reason - // is that we might do something *then* actually jump to the exit. - // For instance, the following block of code: - // ``` - // if cond { break; } else { ... } - // ``` - // - // Gets translated in MIR to something like this: - // ``` - // bb1: { - // if cond -> bb2 else -> bb3; // bb2 is not the real exit - // } - // - // bb2: { - // goto bb4; // bb4 is the real exit - // } - // ``` - register_children_as_loop_exit_candidates( - cfg, - loop_exits, - &fparent_loops.removed_parents, - child, - ); + // Translate this block. Any jumps to the loop header or a merge node will be replaced with + // `continue`/`break`. + let mut block = self.translate_block(&self.block_data[bid].contents); - // Explore, with the filtered parents - compute_loop_exit_candidates( - cfg, - explored, - ordered_loops, - loop_exits, - fparent_loops.remaining_parents, - child, + // Pop the contexts and translate what remains. + while self.special_jump_stack.len() > old_context_depth { + match self.special_jump_stack.pop().unwrap() { + (_, SpecialJump::Loop) => { + block = tgt::Statement::new(block.span, tgt::StatementKind::Loop(block)) + .into_block(); + } + (followed_by, SpecialJump::JumpForward) => { + // We add a `loop { ...; break }` so that we can use `break` to jump forward. + let span = block.span; + block = block.merge( + tgt::Statement::new(span, tgt::StatementKind::Break(0)).into_block(), ); + block = tgt::Statement::new(span, tgt::StatementKind::Loop(block)).into_block(); + // Control-flow that jumps to `followed_by` will break out of the above loop, + // so the target block can just follow this loop. + let followed_by = self.reloop_block(followed_by); + block = block.merge(followed_by); + } + (followed_by, SpecialJump::Fallthrough) => { + // Control-flow that jumps to `followed_by` will reach here, so the target + // block can just be translated here. + let followed_by = self.reloop_block(followed_by); + block = block.merge(followed_by); } } - }) - } -} - -/// See [`compute_loop_switch_exits`] for -/// explanations about what "exits" are. -/// -/// The following function computes the loop exits. It acts as follows. -/// -/// We keep track of a stack of the loops in which we entered. -/// It is very easy to check when we enter a loop: loop entries are destinations -/// of backward edges, which can be spotted with a simple graph exploration (see -/// [`build_cfg_partial_info_edges`]. -/// The criteria to consider whether we exit a loop is the following: -/// - we exit a loop if we go to a block from which we can't reach the loop -/// entry at all -/// - or if we can reach the loop entry, but must use a backward edge which goes -/// to an outer loop -/// -/// It is better explained on the following example: -/// ```text -/// 'outer while i < max { -/// 'inner while j < max { -/// j += 1; -/// } -/// // (i) -/// i += 1; -/// } -/// ``` -/// If we enter the inner loop then go to (i) from the inner loop, we consider -/// that we exited the outer loop because: -/// - we can reach the entry of the inner loop from (i) (by finishing then -/// starting again an iteration of the outer loop) -/// - but doing this requires taking a backward edge which goes to the outer loop -/// -/// Whenever we exit a loop, we save the block we went to as an exit candidate -/// for this loop. Note that there may by many exit candidates. For instance, -/// in the below example: -/// ```text -/// while ... { -/// ... -/// if ... { -/// // We can't reach the loop entry from here: this is an exit -/// // candidate -/// return; -/// } -/// } -/// // This is another exit candidate - and this is the one we want to use -/// // as the "real" exit... -/// ... -/// ``` -/// -/// Also note that it may happen that we go several times to the same exit (if -/// we use breaks for instance): we record the number of times an exit candidate -/// is used. -/// -/// Once we listed all the exit candidates, we find the "best" one for every -/// loop, starting with the outer loops. We start with outer loops because -/// inner loops might use breaks to exit to the exit of outer loops: if we -/// start with the inner loops, the exit which is "natural" for the outer loop -/// might end up being used for one of the inner loops... -/// -/// The best exit is the following one: -/// - it is the one which is used the most times (note that there can be -/// several candidates which are referenced strictly more than once: see the -/// comment below) -/// - if several exits have the same number of occurrences, we choose the one -/// for which we goto the "earliest" (earliest meaning that the goto is close to -/// the loop entry node in the AST). The reason is that all the loops should -/// have an outer if ... then ... else ... which executes the loop body or goes -/// to the exit (note that this is not necessarily the first -/// if ... then ... else ... we find: loop conditions can be arbitrary -/// expressions, containing branchings). -/// -/// # Several candidates for a loop exit: -/// ===================================== -/// There used to be a sanity check to ensure there are no two different -/// candidates with exactly the same number of occurrences and distance from -/// the entry of the loop, if the number of occurrences is > 1. -/// -/// We removed it because it does happen, for instance here (the match -/// introduces an `unreachable` node, and it has the same number of -/// occurrences and the same distance to the loop entry as the `panic` -/// node): -/// -/// ```text -/// pub fn list_nth_mut_loop_pair<'a, T>( -/// mut ls: &'a mut List, -/// mut i: u32, -/// ) -> &'a mut T { -/// loop { -/// match ls { -/// List::Nil => { -/// panic!() // <-- best candidate -/// } -/// List::Cons(x, tl) => { -/// if i == 0 { -/// return x; -/// } else { -/// ls = tl; -/// i -= 1; -/// } -/// } -/// _ => { -/// // Note that Rustc always introduces an unreachable branch after -/// // desugaring matches. -/// unreachable!(), // <-- best candidate -/// } -/// } -/// } -/// } -/// ``` -/// -/// When this happens we choose an exit candidate whose edges don't necessarily -/// lead to an error (above there are none, so we don't choose any exits). Note -/// that this last condition is important to prevent loops from being unnecessarily -/// nested: -/// -/// ```text -/// pub fn nested_loops_enum(step_out: usize, step_in: usize) -> usize { -/// let mut s = 0; -/// -/// for _ in 0..128 { // We don't want this loop to be nested with the loops below -/// s += 1; -/// } -/// -/// for _ in 0..(step_out) { -/// for _ in 0..(step_in) { -/// s += 1; -/// } -/// } -/// -/// s -/// } -/// ``` -fn compute_loop_exits( - ctx: &mut TransformCtx, - body: &src::ExprBody, - cfg: &CfgInfo, -) -> HashMap> { - let mut explored = HashSet::new(); - let mut ordered_loops = Vec::new(); - let mut loop_exits = HashMap::new(); - - // Initialize the loop exits candidates - for loop_id in &cfg.loop_entries { - loop_exits.insert(*loop_id, IndexMap::new()); - } - - // Compute the candidates - compute_loop_exit_candidates( - cfg, - &mut explored, - &mut ordered_loops, - &mut loop_exits, - Vec::new(), - src::BlockId::ZERO, - ); - - { - // Debugging - let candidates: Vec = loop_exits - .iter() - .map(|(loop_id, candidates)| format!("{loop_id} -> {candidates:?}")) - .collect(); - trace!("Loop exit candidates:\n{}", candidates.join("\n")); + } + block } - // Choose one candidate among the potential candidates. - let mut exits: HashSet = HashSet::new(); - let mut chosen_loop_exits: HashMap> = HashMap::new(); - // For every loop - for loop_id in ordered_loops { - // Check the candidates. - // Ignore the candidates which have already been chosen as exits for other - // loops (which should be outer loops). - // We choose the exit with: - // - the most occurrences - // - the least total distance (if there are several possibilities) - // - doesn't necessarily lead to an error (panic, unreachable) - - // First: - // - filter the candidates - // - compute the number of occurrences - // - compute the sum of distances - // TODO: we could simply order by using a lexicographic order - let loop_exits = loop_exits - .get(&loop_id) - .unwrap() - .iter() - // If candidate already selected for another loop: ignore - .filter(|(candidate_id, _)| !exits.contains(candidate_id)) - .map(|(candidate_id, candidate_info)| { - let num_occurrences = candidate_info.occurrences.len(); - let dist_sum = candidate_info.occurrences.iter().sum(); - (*candidate_id, num_occurrences, dist_sum) - }) - .collect_vec(); - - trace!( - "Loop {}: possible exits:\n{}", - loop_id, - loop_exits - .iter() - .map(|(bid, occs, dsum)| format!( - "{bid} -> {{ occurrences: {occs}, dist_sum: {dsum} }}", - )) - .collect::>() - .join("\n") - ); - - // Second: actually select the proper candidate. - - // We find the one with the highest occurrence and the smallest distance - // from the entry of the loop (note that we take care of listing the exit - // candidates in a deterministic order). - let mut best_exit: Option = None; - let mut best_occurrences = 0; - let mut best_dist_sum = std::usize::MAX; - for (candidate_id, occurrences, dist_sum) in &loop_exits { - if (*occurrences > best_occurrences) - || (*occurrences == best_occurrences && *dist_sum < best_dist_sum) - { - best_exit = Some(*candidate_id); - best_occurrences = *occurrences; - best_dist_sum = *dist_sum; - } + // Translate a jump between these two blocks. + fn translate_jump(&mut self, span: Span, to: BlockId) -> tgt::Block { + // The top of the stack is where control-flow goes naturally, no need to add a + // `break`/`continue`. + if let Some((b, _)) = self.special_jump_stack.last() + && *b == to + { + return tgt::Statement::new(span, tgt::StatementKind::Nop).into_block(); } - - let possible_candidates: Vec<_> = loop_exits + let mut depth = 0; + match self + .special_jump_stack .iter() - .filter_map(|(bid, occs, dsum)| { - if *occs == best_occurrences && *dsum == best_dist_sum { - Some(*bid) - } else { - None + .rev() + .map(|(b, ctx)| { + let i = depth; + // Fallthrough blocks don't add a level of loop nesting so they don't count towards + // depth. + if !matches!(ctx, SpecialJump::Fallthrough) { + depth += 1; } + (i, *b, ctx) }) - .collect(); - let num_possible_candidates = loop_exits.len(); - - // If there is exactly one one best candidate, it is easy. - // Otherwise we need to split further. - if num_possible_candidates > 1 { - trace!("Best candidates: {:?}", possible_candidates); - // TODO: if we use a lexicographic order we can merge this with the code - // above. - // Remove the candidates which only lead to errors (panic or unreachable). - let candidates: Vec<_> = possible_candidates - .iter() - .filter(|bid| !cfg.only_reach_error.contains(bid)) - .collect(); - // If there is exactly one candidate we select it - if candidates.len() == 1 { - let exit_id = *candidates[0]; - exits.insert(exit_id); - trace!("Loop {loop_id}: selected the best exit candidate {exit_id}"); - chosen_loop_exits.insert(loop_id, Some(exit_id)); - } else { - // Otherwise we do not select any exit. - // We don't want to select any exit if we are in the below situation - // (all paths lead to errors). We added a sanity check below to - // catch the situations where there are several exits which don't - // lead to errors. - // - // Example: - // ======== - // ``` - // loop { - // match ls { - // List::Nil => { - // panic!() // <-- best candidate - // } - // List::Cons(x, tl) => { - // if i == 0 { - // return x; - // } else { - // ls = tl; - // i -= 1; - // } - // } - // _ => { - // unreachable!(); // <-- best candidate (Rustc introduces an `unreachable` case) - // } - // } - // } - // ``` - // - // Adding this sanity check so that we can see when there are - // several candidates. - let span = body.body[loop_id].terminator.span; // Taking *a* span from the block - sanity_check!(ctx, span, candidates.is_empty()); - trace!( - "Loop {loop_id}: did not select an exit candidate because they all lead to panics" - ); - chosen_loop_exits.insert(loop_id, None); - } - } else { - // Register the exit, if there is one - match best_exit { - None => { - // No exit was found - trace!("Loop {loop_id}: could not find an exit candidate"); - chosen_loop_exits.insert(loop_id, None); - } - Some(exit_id) => { - exits.insert(exit_id); - trace!("Loop {loop_id}: selected the unique exit candidate {exit_id}"); - chosen_loop_exits.insert(loop_id, Some(exit_id)); - } - } - } - } - - // Return the chosen exits - trace!("Chosen loop exits: {:?}", chosen_loop_exits); - chosen_loop_exits -} - -/// Information used to compute the switch exits. -/// We compute this information for every block in the graph. -/// Note that we make sure to use immutable sets because we rely a lot -/// on cloning. -#[derive(Debug, Clone)] -struct BlocksInfo { - id: src::BlockId, - /// All the successors of the block - succs: BTreeSet, - /// Let's say we put a quantity of water equal to 1 on the block, and the - /// water flows downards. Whenever there is a branching, the quantity of - /// water gets equally divided between the branches. When the control flows - /// join, we put the water back together. The set below computes the amount - /// of water received by each descendant of the node. - /// - /// TODO: there must be a known algorithm which computes this, right?... - /// This is exactly this problems: - /// - /// TODO: the way I compute this is not efficient. - /// - /// Remark: in order to rank the nodes, we also use the negation of the - /// rank given by the topological order. The last elements of the set - /// have the highest flow, that is they are the nodes to which the maximum - /// number of paths converge. If several nodes have the same flow, we want - /// to take the highest one in the hierarchy: hence the use of the inverse - /// of the topological rank. - /// - /// Ex.: - /// ```text - /// A -- we start here - /// | - /// |--------------------------------------- - /// | | | | - /// B:(0.25,-1) C:(0.25,-2) D:(0.25,-3) E:(0.25,-4) - /// | | | - /// |-------------------------- - /// | - /// F:(0.75,-5) - /// | - /// | - /// G:(0.75,-6) - /// ``` - /// The "best" node (with the highest (flow, rank) in the graph above is F. - flow: BTreeSet, -} - -/// Create an [OrdBlockId] from a block id and a rank given by a map giving -/// a sort (topological in our use cases) over the graph. -fn make_ord_block_id( - block_id: src::BlockId, - sort_map: &HashMap, -) -> OrdBlockId { - let rank = *sort_map.get(&block_id).unwrap(); - OrdBlockId { id: block_id, rank } -} - -/// Compute [BlocksInfo] for every block in the graph. -/// This information is then used to compute the switch exits. -fn compute_switch_exits_explore( - cfg: &CfgInfo, - tsort_map: &HashMap, - memoized: &mut HashMap, - block_id: src::BlockId, -) { - // Check if we already computer the info - if memoized.get(&block_id).is_some() { - return; - } - - // Compute the block information for the children - let children_ids: Vec = cfg.cfg_no_be.neighbors(block_id).collect_vec(); - children_ids - .iter() - .for_each(|bid| compute_switch_exits_explore(cfg, tsort_map, memoized, *bid)); - - // Retrieve the information - let children: Vec<&BlocksInfo> = children_ids - .iter() - .map(|bid| memoized.get(bid).unwrap()) - .collect(); - - // Compute the successors - // Add the children themselves in their sets of successors - let all_succs: BTreeSet = children.iter().fold(BTreeSet::new(), |acc, s| { - // Add the successors to the accumulator - let mut acc: BTreeSet<_> = acc.union(&s.succs).copied().collect(); - // Add the child itself - acc.insert(make_ord_block_id(s.id, tsort_map)); - acc - }); - - // Compute the "flows" (if there are children) - // TODO: this is computationally expensive... - let mut flow: HashMap = HashMap::new(); - - if children.len() > 0 { - // We need to divide the initial flow equally between the children - let factor = BigRational::new(BigInt::from(1), BigInt::from(children.len())); - - // Small helper - let mut add_to_flow = |(id, f0): (src::BlockId, (BigRational, isize))| match flow.get(&id) { - None => flow.insert(id, f0), - Some(f1) => { - let f = f0.0 + f1.0.clone(); - assert!(f0.1 == f1.1); - flow.insert(id, (f, f0.1)) - } - }; - - // For each child, multiply the flows of its own children by the ratio, - // and add. - for child in children { - // First, add the child itself - let rank = isize::try_from(*tsort_map.get(&child.id).unwrap()).unwrap(); - add_to_flow((child.id, (factor.clone(), -rank))); - - // Then add its successors - for child1 in &child.flow { - add_to_flow(( - child1.id, - (factor.clone() * child1.rank.0.clone(), child1.rank.1), - )); + .find(|(_, b, _)| *b == to) + { + Some((depth, _, context)) => { + let kind = match context { + // Must only happen at the top of the stack, caught above. + SpecialJump::Fallthrough => unreachable!(), + SpecialJump::Loop => tgt::StatementKind::Continue(depth), + SpecialJump::JumpForward => tgt::StatementKind::Break(depth), + }; + tgt::Statement::new(span, kind).into_block() } + None => self.reloop_block(to), } } - // Put everything in an ordered set: the first block id will be the one with - // the highest flow, and in case of equality it will be the one with the - // smallest block id. - let flow: BTreeSet = flow - .into_iter() - .map(|(id, rank)| BlockWithRank { rank, id }) - .collect(); - - trace!("block: {block_id}, all successors: {all_succs:?}, flow: {flow:?}"); - - // Memoize - let info = BlocksInfo { - id: block_id, - succs: all_succs, - flow, - }; - memoized.insert(block_id, info.clone()); -} - -/// Auxiliary helper -/// -/// Check if it is possible to reach the exit of an outer switch from `start_bid` -/// without going through the `exit_candidate`. We use the graph without -/// backward edges. -fn can_reach_outer_exit( - cfg: &CfgInfo, - outer_exits: &HashSet, - start_bid: src::BlockId, - exit_candidate: src::BlockId, -) -> bool { - // The stack of blocks - let mut stack: Vec = vec![start_bid]; - let mut explored: HashSet = HashSet::new(); - - while let Some(bid) = stack.pop() { - // Check if already explored - if explored.contains(&bid) { - break; - } - explored.insert(bid); - - // Check if this is the exit candidate - if bid == exit_candidate { - // Stop exploring - break; - } - - // Check if this is an outer exit - if outer_exits.contains(&bid) { - return true; - } - - // Add the children to the stack - for child in cfg.cfg_no_be.neighbors(bid) { - stack.push(child); + fn translate_block(&mut self, block: &src::BlockData) -> tgt::Block { + // Translate the statements inside the block + let statements = block + .statements + .iter() + .map(|st| translate_statement(st)) + .collect_vec(); + let terminator = self.translate_terminator(&block.terminator); + // Prepend the statements to the terminator. + if let Some(st) = tgt::Block::from_seq(statements) { + st.merge(terminator) + } else { + terminator } } - false -} - -/// See [`compute_loop_switch_exits`] for -/// explanations about what "exits" are. -/// -/// In order to compute the switch exits, we simply recursively compute a -/// topologically ordered set of "filtered successors" as follows (note -/// that we work in the CFG *without* back edges): -/// - for a block which doesn't branch (only one successor), the filtered -/// successors is the set of reachable nodes. -/// - for a block which branches, we compute the nodes reachable from all -/// the children, and find the "best" intersection between those. -/// Note that we find the "best" intersection (a pair of branches which -/// maximize the intersection of filtered successors) because some branches -/// might never join the control-flow of the other branches, if they contain -/// a `break`, `return`, `panic`, etc., like here: -/// ```text -/// if b { x = 3; } { return; } -/// y += x; -/// ... -/// ``` -/// Note that with nested switches, the branches of the inner switches might -/// goto the exits of the outer switches: for this reason, we give precedence -/// to the outer switches. -fn compute_switch_exits( - cfg: &CfgInfo, - tsort_map: &HashMap, -) -> HashMap> { - // Compute the successors info map, starting at the root node - let mut succs_info_map = HashMap::new(); - trace!( - "- cfg.cfg:\n{:?}\n- cfg.cfg_no_be:\n{:?}\n- cfg.switch_blocks:\n{:?}", - cfg.cfg, cfg.cfg_no_be, cfg.switch_blocks - ); - let _ = compute_switch_exits_explore(cfg, tsort_map, &mut succs_info_map, src::BlockId::ZERO); - - // We need to give precedence to the outer switches: we thus iterate - // over the switch blocks in topological order. - let mut sorted_switch_blocks: BTreeSet = BTreeSet::new(); - for bid in cfg.switch_blocks.iter() { - sorted_switch_blocks.insert(make_ord_block_id(*bid, tsort_map)); - } - trace!("sorted_switch_blocks: {:?}", sorted_switch_blocks); - - // Debugging: print all the successors - { - trace!("Successors info:\n{}\n", { - let mut out = vec![]; - for (bid, info) in &succs_info_map { - out.push( - format!( - "{} -> {{succs: {:?}, flow: {:?}}}", - bid, &info.succs, &info.flow - ) - .to_string(), - ); + fn translate_terminator(&mut self, terminator: &src::Terminator) -> tgt::Block { + let src_span = terminator.span; + match &terminator.kind { + src::TerminatorKind::Abort(kind) => { + tgt::Statement::new(src_span, tgt::StatementKind::Abort(kind.clone())).into_block() } - out.join("\n") - }); - } - - // For every node which is a switch, retrieve the exit. - // As the set of intersection of successors is topologically sorted, the - // exit should be the first node in the set (if the set is non empty). - // Also, we need to explore the nodes in topological order, to give - // precedence to the outer switches. - let mut exits_set = HashSet::new(); - let mut ord_exits_set = BTreeSet::new(); - let mut exits = HashMap::new(); - for bid in sorted_switch_blocks { - trace!("Finding exit candidate for: {bid:?}"); - let bid = bid.id; - let info = succs_info_map.get(&bid).unwrap(); - let succs = &info.flow; - // Find the best successor: this is the last one (with the highest flow, - // and the highest reverse topological rank). - if succs.is_empty() { - trace!("{bid:?} has no successors"); - exits.insert(bid, None); - } else { - // We have an exit candidate: check that it was not already - // taken by an external switch - let exit = succs.last().unwrap(); - trace!("{bid:?} has an exit candidate: {exit:?}"); - if exits_set.contains(&exit.id) { - trace!("Ignoring the exit candidate because already taken by an external switch"); - exits.insert(bid, None); - } else { - // It was not taken by an external switch. - // - // We must check that we can't reach the exit of an external - // switch from one of the branches, without going through the - // exit candidate. - // We do this by simply checking that we can't reach any exits - // (and use the fact that we explore the switch by using a - // topological order to not discard valid exit candidates). - // - // The reason is that it can lead to code like the following: - // ``` - // if ... { // if #1 - // if ... { // if #2 - // ... - // // here, we have a `goto b1`, where b1 is the exit - // // of if #2: we thus stop translating the blocks. - // } - // else { - // ... - // // here, we have a `goto b2`, where b2 is the exit - // // of if #1: we thus stop translating the blocks. - // } - // // We insert code for the block b1 here (which is the exit of - // // the exit of if #2). However, this block should only - // // be executed in the branch "then" of the if #2, not in - // // the branch "else". - // ... - // } - // else { - // ... - // } - // ``` - - // First: we do a quick check (does the set of all successors - // intersect the set of exits for outer blocks?). If yes, we do - // a more precise analysis: we check if we can reach the exit - // *without going through* the exit candidate. - if info.succs.intersection(&ord_exits_set).next().is_none() - || !can_reach_outer_exit(cfg, &exits_set, bid, exit.id) - { - trace!("Keeping the exit candidate"); - // No intersection: ok - exits_set.insert(exit.id); - ord_exits_set.insert(make_ord_block_id(exit.id, tsort_map)); - exits.insert(bid, Some(exit.id)); - } else { - trace!( - "Ignoring the exit candidate because of an intersection with external switches" - ); - exits.insert(bid, None); - } + src::TerminatorKind::Return => { + tgt::Statement::new(src_span, tgt::StatementKind::Return).into_block() } - } - } - - exits -} - -/// The exits of a graph -#[derive(Debug, Clone)] -struct ExitInfo { - /// The loop exits - loop_exits: HashMap>, - /// Some loop exits actually belong to outer switches. We still need - /// to track them in the loop exits, in order to know when we should - /// insert a break. However, we need to make sure we don't add the - /// corresponding block in a sequence, after having translated the - /// loop, like so: - /// ```text - /// loop { - /// loop_body - /// }; - /// exit_blocks // OK if the exit "belongs" to the loop - /// ``` - /// - /// In case the exit doesn't belong to the loop: - /// ```text - /// if b { - /// loop { - /// loop_body - /// } // no exit blocks after the loop - /// } - /// else { - /// ... - /// }; - /// exit_blocks // the exit blocks are here - /// ``` - owned_loop_exits: HashMap>, - /// The switch exits. - /// Note that the switch exits are always owned. - owned_switch_exits: HashMap>, -} - -/// Compute the exits for the loops and the switches (switch on integer and -/// if ... then ... else ...). We need to do this because control-flow in MIR -/// is destructured: we have gotos everywhere. -/// -/// Let's consider the following piece of code: -/// ```text -/// if cond1 { ... } else { ... }; -/// if cond2 { ... } else { ... }; -/// ``` -/// Once converted to MIR, the control-flow is destructured, which means we -/// have gotos everywhere. When reconstructing the control-flow, we have -/// to be careful about the point where we should join the two branches of -/// the first if. -/// For instance, if we don't notice they should be joined at some point (i.e, -/// whatever the branch we take, there is a moment when we go to the exact -/// same place, just before the second if), we might generate code like -/// this, with some duplicata: -/// ```text -/// if cond1 { ...; if cond2 { ... } else { ...} } -/// else { ...; if cond2 { ... } else { ...} } -/// ``` -/// -/// Such a reconstructed program is valid, but it is definitely non-optimal: -/// it is very different from the original program (making it less clean and -/// clear), more bloated, and might involve duplicating the proof effort. -/// -/// For this reason, we need to find the "exit" of the first loop, which is -/// the point where the two branches join. Note that this can be a bit tricky, -/// because there may be more than two branches (if we do `switch(x) { ... }`), -/// and some of them might not join (if they contain a `break`, `panic`, -/// `return`, etc.). -/// -/// Finally, some similar issues arise for loops. For instance, let's consider -/// the following piece of code: -/// ```text -/// while cond1 { -/// e1; -/// if cond2 { -/// break; -/// } -/// e2; -/// } -/// e3; -/// return; -/// ``` -/// -/// Note that in MIR, the loop gets desugared to an if ... then ... else .... -/// From the MIR, We want to generate something like this: -/// ```text -/// loop { -/// if cond1 { -/// e1; -/// if cond2 { -/// break; -/// } -/// e2; -/// continue; -/// } -/// else { -/// break; -/// } -/// }; -/// e3; -/// return; -/// ``` -/// -/// But if we don't pay attention, we might end up with that, once again with -/// duplications: -/// ```text -/// loop { -/// if cond1 { -/// e1; -/// if cond2 { -/// e3; -/// return; -/// } -/// e2; -/// continue; -/// } -/// else { -/// e3; -/// return; -/// } -/// } -/// ``` -/// We thus have to notice that if the loop condition is false, we goto the same -/// block as when following the goto introduced by the break inside the loop, and -/// this block is dubbed the "loop exit". -/// -/// The following function thus computes the "exits" for loops and switches, which -/// are basically the points where control-flow joins. -fn compute_loop_switch_exits( - ctx: &mut TransformCtx, - body: &src::ExprBody, - cfg_info: &CfgInfo, -) -> ExitInfo { - // Use the CFG without backward edges to topologically sort the nodes. - // Note that `toposort` returns `Err` if and only if it finds cycles (which - // can't happen). - let tsorted: Vec = toposort(&cfg_info.cfg_no_be, None).unwrap(); - - // Build the map: block id -> topological sort rank - let tsort_map: HashMap = tsorted - .into_iter() - .enumerate() - .map(|(i, block_id)| (block_id, i)) - .collect(); - trace!("tsort_map:\n{:?}", tsort_map); - - // Compute the loop exits - let loop_exits = compute_loop_exits(ctx, body, cfg_info); - trace!("loop_exits:\n{:?}", loop_exits); - - // Compute the switch exits - let switch_exits = compute_switch_exits(cfg_info, &tsort_map); - trace!("switch_exits:\n{:?}", switch_exits); - - // Compute the exit info - let mut exit_info = ExitInfo { - loop_exits: HashMap::new(), - owned_loop_exits: HashMap::new(), - owned_switch_exits: HashMap::new(), - }; - - // We need to give precedence to the outer switches and loops: we thus iterate - // over the blocks in topological order. - let mut sorted_blocks: BTreeSet = BTreeSet::new(); - for bid in cfg_info - .loop_entries - .iter() - .chain(cfg_info.switch_blocks.iter()) - { - sorted_blocks.insert(make_ord_block_id(*bid, &tsort_map)); - } - - // Keep track of the exits which were already attributed - let mut all_exits = HashSet::new(); - - // Put all this together - for bid in sorted_blocks { - let bid = bid.id; - // Check if loop or switch block - if cfg_info.loop_entries.contains(&bid) { - // This is a loop. - // - // For loops, we always register the exit (if there is one). - // However, the exit may be owned by an outer switch (note - // that we already took care of spreading the exits between - // the inner/outer loops) - let exit_id = loop_exits.get(&bid).unwrap(); - exit_info.loop_exits.insert(bid, *exit_id); - - // Check if we "own" the exit - match exit_id { - None => { - // No exit - exit_info.owned_loop_exits.insert(bid, None); - } - Some(exit_id) => { - if all_exits.contains(exit_id) { - // We don't own it - exit_info.owned_loop_exits.insert(bid, None); - } else { - // We own it - exit_info.owned_loop_exits.insert(bid, Some(*exit_id)); - all_exits.insert(*exit_id); - } - } + src::TerminatorKind::UnwindResume => { + tgt::Statement::new(src_span, tgt::StatementKind::Abort(AbortKind::Panic(None))) + .into_block() } - } else { - // For switches: check that the exit was not already given to a - // loop - let exit_id = switch_exits.get(&bid).unwrap(); - - match exit_id { - None => { - // No exit - exit_info.owned_switch_exits.insert(bid, None); - } - Some(exit_id) => { - if all_exits.contains(exit_id) { - // We don't own it - exit_info.owned_switch_exits.insert(bid, None); - } else { - // We own it - exit_info.owned_switch_exits.insert(bid, Some(*exit_id)); - all_exits.insert(*exit_id); - } - } + src::TerminatorKind::Call { + call, + target, + on_unwind: _, + } => { + // TODO: Have unwinds in the LLBC + let mut block = self.translate_jump(src_span, *target); + let st = tgt::Statement::new(src_span, tgt::StatementKind::Call(call.clone())); + block.statements.insert(0, st); + block } - } - } - - exit_info -} - -fn get_goto_kind( - exits_info: &ExitInfo, - parent_loops: &Vec, - switch_exit_blocks: &HashSet, - next_block_id: src::BlockId, -) -> GotoKind { - // First explore the parent loops in revert order - for (i, loop_id) in parent_loops.iter().rev().enumerate() { - // If we goto a loop entry node: this is a 'continue' - if next_block_id == *loop_id { - return GotoKind::Continue(i); - } else { - // If we goto a loop exit node: this is a 'break' - if let Some(exit_id) = exits_info.loop_exits.get(loop_id).unwrap() { - if next_block_id == *exit_id { - return GotoKind::Break(i); - } + src::TerminatorKind::Drop { + place, + tref, + target, + on_unwind: _, + } => { + // TODO: Have unwinds in the LLBC + let mut block = self.translate_jump(src_span, *target); + let st = tgt::Statement::new( + src_span, + tgt::StatementKind::Drop(place.clone(), tref.clone()), + ); + block.statements.insert(0, st); + block } - } - } - - // Check if the goto exits the current block - if switch_exit_blocks.contains(&next_block_id) { - return GotoKind::ExitBlock; - } - - // Default - GotoKind::Goto -} - -enum GotoKind { - Break(usize), - Continue(usize), - ExitBlock, - Goto, -} - -/// `parent_span`: we need some span data for the new statement. -/// We use the one for the parent terminator. -fn translate_child_block( - info: &mut BlockInfo<'_>, - parent_loops: &Vec, - switch_exit_blocks: &HashSet, - parent_span: Span, - child_id: src::BlockId, -) -> Option { - // Check if this is a backward call - match get_goto_kind(info.exits_info, parent_loops, switch_exit_blocks, child_id) { - GotoKind::Break(index) => { - let st = tgt::StatementKind::Break(index); - Some(tgt::Statement::new(parent_span, st).into_block()) - } - GotoKind::Continue(index) => { - let st = tgt::StatementKind::Continue(index); - Some(tgt::Statement::new(parent_span, st).into_block()) - } - // If we are going to an exit block we simply ignore the goto - GotoKind::ExitBlock => None, - GotoKind::Goto => { - // "Standard" goto: just recursively translate - ensure_sufficient_stack(|| { - Some(translate_block( - info, - parent_loops, - switch_exit_blocks, - child_id, - )) - }) - } - } -} - -fn opt_block_unwrap_or_nop(span: Span, opt_block: Option) -> tgt::Block { - opt_block.unwrap_or_else(|| tgt::Statement::new(span, tgt::StatementKind::Nop).into_block()) -} - -fn translate_statement(st: &src::Statement) -> Option { - let src_span = st.span; - let st = match st.kind.clone() { - src::StatementKind::Assign(place, rvalue) => tgt::StatementKind::Assign(place, rvalue), - src::StatementKind::SetDiscriminant(place, variant_id) => { - tgt::StatementKind::SetDiscriminant(place, variant_id) - } - src::StatementKind::CopyNonOverlapping(copy) => { - tgt::StatementKind::CopyNonOverlapping(copy) - } - src::StatementKind::StorageLive(var_id) => tgt::StatementKind::StorageLive(var_id), - src::StatementKind::StorageDead(var_id) => tgt::StatementKind::StorageDead(var_id), - src::StatementKind::Deinit(place) => tgt::StatementKind::Deinit(place), - src::StatementKind::Assert(assert) => tgt::StatementKind::Assert(assert), - src::StatementKind::Nop => tgt::StatementKind::Nop, - src::StatementKind::Error(s) => tgt::StatementKind::Error(s), - }; - Some(tgt::Statement::new(src_span, st)) -} - -fn translate_terminator( - info: &mut BlockInfo<'_>, - parent_loops: &Vec, - switch_exit_blocks: &HashSet, - terminator: &src::Terminator, -) -> tgt::Block { - let src_span = terminator.span; - - match &terminator.kind { - src::TerminatorKind::Abort(kind) => { - tgt::Statement::new(src_span, tgt::StatementKind::Abort(kind.clone())).into_block() - } - src::TerminatorKind::Return => { - tgt::Statement::new(src_span, tgt::StatementKind::Return).into_block() - } - src::TerminatorKind::UnwindResume => { - tgt::Statement::new(src_span, tgt::StatementKind::Abort(AbortKind::Panic(None))) - .into_block() - } - src::TerminatorKind::Call { - call, - target, - on_unwind: _, - } => { - // TODO: Have unwinds in the LLBC - let target_block = translate_child_block( - info, - parent_loops, - switch_exit_blocks, - terminator.span, - *target, - ); - let mut block = opt_block_unwrap_or_nop(terminator.span, target_block); - let st = tgt::Statement::new(src_span, tgt::StatementKind::Call(call.clone())); - block.statements.insert(0, st); - block - } - src::TerminatorKind::Drop { - place, - tref, - target, - on_unwind: _, - } => { - // TODO: Have unwinds in the LLBC - let target_block = translate_child_block( - info, - parent_loops, - switch_exit_blocks, - terminator.span, - *target, - ); - let mut block = opt_block_unwrap_or_nop(terminator.span, target_block); - let st = tgt::Statement::new( - src_span, - tgt::StatementKind::Drop(place.clone(), tref.clone()), - ); - block.statements.insert(0, st); - block - } - src::TerminatorKind::Goto { target } => { - let block = translate_child_block( - info, - parent_loops, - switch_exit_blocks, - terminator.span, - *target, - ); - let block = opt_block_unwrap_or_nop(terminator.span, block); - block - } - src::TerminatorKind::Switch { discr, targets } => { - // Translate the target expressions - let switch = match &targets { - src::SwitchTargets::If(then_tgt, else_tgt) => { - // Translate the children expressions - let then_block = translate_child_block( - info, - parent_loops, - switch_exit_blocks, - terminator.span, - *then_tgt, - ); - // We use the terminator span information in case then - // then statement is `None` - let then_block = opt_block_unwrap_or_nop(terminator.span, then_block); - let else_block = translate_child_block( - info, - parent_loops, - switch_exit_blocks, - terminator.span, - *else_tgt, - ); - let else_block = opt_block_unwrap_or_nop(terminator.span, else_block); - - // Translate - tgt::Switch::If(discr.clone(), then_block, else_block) - } - src::SwitchTargets::SwitchInt(int_ty, targets, otherwise) => { - // Note that some branches can be grouped together, like - // here: - // ``` - // match e { - // E::V1 | E::V2 => ..., // Grouped - // E::V3 => ... - // } - // ``` - // We detect this by checking if a block has already been - // translated as one of the branches of the switch. - // - // Rk.: note there may be intermediate gotos depending - // on the MIR we use. Typically, we manage to detect the - // grouped branches with Optimized MIR, but not with Promoted - // MIR. See the comment in "tests/src/matches.rs". - - // We link block ids to: - // - vector of matched integer values - // - translated blocks - let mut branches: IndexMap, tgt::Block)> = - IndexMap::new(); - - // Translate the children expressions - for (v, bid) in targets.iter() { - // Check if the block has already been translated: - // if yes, it means we need to group branches - if branches.contains_key(bid) { - // Already translated: add the matched value to - // the list of values - let branch = branches.get_mut(bid).unwrap(); - branch.0.push(v.clone()); - } else { - // Not translated: translate it - let block = translate_child_block( - info, - parent_loops, - switch_exit_blocks, - terminator.span, - *bid, - ); - // We use the terminator span information in case then - // then statement is `None` - let block = opt_block_unwrap_or_nop(terminator.span, block); - branches.insert(*bid, (vec![v.clone()], block)); - } + src::TerminatorKind::Goto { target } => self.translate_jump(src_span, *target), + src::TerminatorKind::Switch { discr, targets } => { + let switch = match &targets { + src::SwitchTargets::If(then_tgt, else_tgt) => { + let then_block = self.translate_jump(src_span, *then_tgt); + let else_block = self.translate_jump(src_span, *else_tgt); + tgt::Switch::If(discr.clone(), then_block, else_block) } - let targets_blocks: Vec<(Vec, tgt::Block)> = - branches.into_iter().map(|(_, x)| x).collect(); - - let otherwise_block = translate_child_block( - info, - parent_loops, - switch_exit_blocks, - terminator.span, - *otherwise, - ); - // We use the terminator span information in case then - // then statement is `None` - let otherwise_block = opt_block_unwrap_or_nop(terminator.span, otherwise_block); + src::SwitchTargets::SwitchInt(int_ty, targets, otherwise) => { + // Note that some branches can be grouped together, like + // here: + // ``` + // match e { + // E::V1 | E::V2 => ..., // Grouped + // E::V3 => ... + // } + // ``` + // We detect this by checking if a block has already been + // translated as one of the branches of the switch. + + // We map each block ids to a vector of matched integer values that + // lead to that block. + let mut branches: IndexMap> = IndexMap::new(); + for (v, tgt) in targets.iter() { + branches.entry(*tgt).or_default().push(v.clone()); + } - // Translate - tgt::Switch::SwitchInt(discr.clone(), *int_ty, targets_blocks, otherwise_block) - } - }; + let targets_blocks: Vec<(Vec, tgt::Block)> = branches + .into_iter() + .map(|(tgt, values)| { + let block = self.translate_jump(src_span, tgt); + (values, block) + }) + .collect(); + let otherwise_block = self.translate_jump(src_span, *otherwise); + + tgt::Switch::SwitchInt( + discr.clone(), + *int_ty, + targets_blocks, + otherwise_block, + ) + } + }; - // Return - let span = tgt::combine_switch_targets_span(&switch); - let span = combine_span(&src_span, &span); - let st = tgt::StatementKind::Switch(switch); - tgt::Statement::new(span, st).into_block() + let span = tgt::combine_switch_targets_span(&switch); + let span = combine_span(&src_span, &span); + let st = tgt::StatementKind::Switch(switch); + tgt::Statement::new(span, st).into_block() + } } } } -/// Remark: some values are boxed (here, the returned statement) so that they -/// are allocated on the heap. This reduces stack usage (we had problems with -/// stack overflows in the past). A more efficient solution would be to use loops -/// to make this code constant space, but that would require a serious rewriting. -fn translate_block( - info: &mut BlockInfo<'_>, - parent_loops: &Vec, - switch_exit_blocks: &HashSet, - block_id: src::BlockId, -) -> tgt::Block { - // If the user activated this check: check that we didn't already translate - // this block, and insert the block id in the set of already translated blocks. - trace!( - "Parent loops: {:?}, Parent switch exits: {:?}, Block id: {}", - parent_loops, switch_exit_blocks, block_id - ); - info.explored.insert(block_id); - - let block = &info.body.body[block_id]; - - // Check if we enter a loop: if so, update parent_loops and the current_exit_block - let is_loop = info.cfg.loop_entries.contains(&block_id); - let mut nparent_loops: Vec; - let nparent_loops = if info.cfg.loop_entries.contains(&block_id) { - nparent_loops = parent_loops.clone(); - nparent_loops.push(block_id); - &nparent_loops - } else { - parent_loops - }; - - // If we enter a switch or a loop, we need to check if we own the exit - // block, in which case we need to append it to the loop/switch body - // in a sequence - let is_switch = block.terminator.kind.is_switch(); - let next_block = if is_loop { - *info.exits_info.owned_loop_exits.get(&block_id).unwrap() - } else if is_switch { - *info.exits_info.owned_switch_exits.get(&block_id).unwrap() - } else { - None - }; - - // If we enter a switch, add the exit block to the set - // of outer exit blocks - let nswitch_exit_blocks = if is_switch { - let mut nexit_blocks = switch_exit_blocks.clone(); - match next_block { - None => nexit_blocks, - Some(bid) => { - nexit_blocks.insert(bid); - nexit_blocks - } - } - } else { - switch_exit_blocks.clone() - }; - - // Translate the terminator and the subsequent blocks. - // Note that this terminator is an option: we might ignore it - // (if it is an exit). - - let terminator = - translate_terminator(info, nparent_loops, &nswitch_exit_blocks, &block.terminator); - - // Translate the statements inside the block - let statements = block - .statements - .iter() - .filter_map(|st| translate_statement(st)) - .collect_vec(); - - // Prepend the statements to the terminator. - let mut block = if let Some(st) = tgt::Block::from_seq(statements) { - st.merge(terminator) - } else { - terminator +fn translate_body(ctx: &mut TransformCtx, body: &mut gast::Body) { + let Body::Unstructured(src_body) = body else { + panic!("Called `ullbc_to_llbc` on an already restructured body") }; + trace!("About to translate to ullbc: {:?}", src_body.span); - if is_loop { - // Put the loop body inside a `Loop`. - block = tgt::Statement::new(block.span, tgt::StatementKind::Loop(block)).into_block() - } else if !is_switch { - assert!(next_block.is_none()); - } - - // Concatenate the exit expression, if needs be - if let Some(exit_block_id) = next_block { - let next_block = ensure_sufficient_stack(|| { - translate_block(info, parent_loops, switch_exit_blocks, exit_block_id) - }); - block = block.merge(next_block); - } - - block -} - -fn translate_body_aux(ctx: &mut TransformCtx, src_body: &src::ExprBody) -> tgt::ExprBody { - // Explore the function body to create the control-flow graph without backward - // edges, and identify the loop entries (which are destinations of backward edges). - let cfg_info = match build_cfg_info(src_body) { - Ok(cfg_info) => cfg_info, + let start_block = BlockId::ZERO; + let mut reloop_ctx = match ReloopCtx::new(src_body, start_block) { + Ok(reloop_ctx) => reloop_ctx, Err(Irreducible(bid)) => { let span = src_body.body[bid].terminator.span; register_error!( @@ -1728,43 +442,15 @@ fn translate_body_aux(ctx: &mut TransformCtx, src_body: &src::ExprBody) -> tgt:: panic!("can't reconstruct irreducible control-flow") } }; - trace!("cfg_info: {:?}", cfg_info); - - // Find the exit block for all the loops and switches, if such an exit point - // exists. - let exits_info = compute_loop_switch_exits(ctx, src_body, &cfg_info); - - // Debugging - trace!("exits_info:\n{:?}", exits_info); - - // Translate the body by reconstructing the loops and the - // conditional branchings. - // Note that we shouldn't get `None`. - let mut explored = HashSet::new(); - let mut info = BlockInfo { - cfg: &cfg_info, - body: src_body, - exits_info: &exits_info, - explored: &mut explored, - }; - let tgt_body = translate_block(&mut info, &Vec::new(), &HashSet::new(), src::BlockId::ZERO); + reloop_ctx.detect_trivial_merges(start_block, None); + let tgt_body = reloop_ctx.reloop_block(start_block); - tgt::ExprBody { + *body = Body::Structured(tgt::ExprBody { span: src_body.span, - locals: src_body.locals.clone(), + locals: reloop_ctx.locals, comments: src_body.comments.clone(), body: tgt_body, - } -} - -fn translate_body(ctx: &mut TransformCtx, body: &mut gast::Body) { - use gast::Body::{Structured, Unstructured}; - let Unstructured(src_body) = body else { - panic!("Called `ullbc_to_llbc` on an already restructured body") - }; - trace!("About to translate to ullbc: {:?}", src_body.span); - let tgt_body = translate_body_aux(ctx, src_body); - *body = Structured(tgt_body); + }); } pub struct Transform; diff --git a/charon/tests/ui/arrays.out b/charon/tests/ui/arrays.out index 8f9831ce1..2683261da 100644 --- a/charon/tests/ui/arrays.out +++ b/charon/tests/ui/arrays.out @@ -1606,36 +1606,34 @@ pub fn sum<'_0>(@1: &'_0 (Slice)) -> u32 storage_dead(@7) @4 := move (@5) < move (@6) if move (@4) { + storage_dead(@6) + storage_dead(@5) + storage_live(@8) + storage_live(@9) + @9 := copy (i@3) + storage_live(@12) + @12 := &*(s@1) with_metadata(copy (s@1.metadata)) + storage_live(@13) + @13 := @SliceIndexShared<'_, u32>(move (@12), copy (@9)) + @8 := copy (*(@13)) + @10 := copy (sum@2) panic.+ copy (@8) + sum@2 := move (@10) + storage_dead(@8) + storage_dead(@9) + @11 := copy (i@3) panic.+ const (1 : usize) + i@3 := move (@11) + storage_dead(@4) } else { - break 0 + storage_dead(@6) + storage_dead(@5) + storage_dead(@4) + @0 := copy (sum@2) + storage_dead(i@3) + storage_dead(sum@2) + return } - storage_dead(@6) - storage_dead(@5) - storage_live(@8) - storage_live(@9) - @9 := copy (i@3) - storage_live(@12) - @12 := &*(s@1) with_metadata(copy (s@1.metadata)) - storage_live(@13) - @13 := @SliceIndexShared<'_, u32>(move (@12), copy (@9)) - @8 := copy (*(@13)) - @10 := copy (sum@2) panic.+ copy (@8) - sum@2 := move (@10) - storage_dead(@8) - storage_dead(@9) - @11 := copy (i@3) panic.+ const (1 : usize) - i@3 := move (@11) - storage_dead(@4) - continue 0 } - storage_dead(@6) - storage_dead(@5) - storage_dead(@4) - @0 := copy (sum@2) - storage_dead(i@3) - storage_dead(sum@2) - return } // Full name: test_crate::sum2 @@ -1686,72 +1684,70 @@ pub fn sum2<'_0, '_1>(@1: &'_0 (Slice), @2: &'_1 (Slice)) -> u32 storage_dead(@8) @4 := move (@5) == move (@7) if move (@4) { + storage_dead(@7) + storage_dead(@5) + storage_dead(@4) + storage_live(i@9) + i@9 := const (0 : usize) + loop { + storage_live(@10) + storage_live(@11) + @11 := copy (i@9) + storage_live(@12) + storage_live(@13) + @13 := &*(s@1) with_metadata(copy (s@1.metadata)) + @12 := len<'_, u32>[{built_in impl Sized for u32}](move (@13)) + storage_dead(@13) + @10 := move (@11) < move (@12) + if move (@10) { + storage_dead(@12) + storage_dead(@11) + storage_live(@14) + storage_live(@15) + storage_live(@16) + @16 := copy (i@9) + storage_live(@24) + @24 := &*(s@1) with_metadata(copy (s@1.metadata)) + storage_live(@25) + @25 := @SliceIndexShared<'_, u32>(move (@24), copy (@16)) + @15 := copy (*(@25)) + storage_live(@17) + storage_live(@18) + @18 := copy (i@9) + storage_live(@22) + @22 := &*(s2@2) with_metadata(copy (s2@2.metadata)) + storage_live(@23) + @23 := @SliceIndexShared<'_, u32>(move (@22), copy (@18)) + @17 := copy (*(@23)) + @19 := copy (@15) panic.+ copy (@17) + @14 := move (@19) + storage_dead(@17) + storage_dead(@15) + @20 := copy (sum@3) panic.+ copy (@14) + sum@3 := move (@20) + storage_dead(@14) + storage_dead(@18) + storage_dead(@16) + @21 := copy (i@9) panic.+ const (1 : usize) + i@9 := move (@21) + storage_dead(@10) + } + else { + storage_dead(@12) + storage_dead(@11) + storage_dead(@10) + @0 := copy (sum@3) + storage_dead(i@9) + storage_dead(sum@3) + return + } + } } else { storage_dead(@7) storage_dead(@5) panic(core::panicking::panic) } - storage_dead(@7) - storage_dead(@5) - storage_dead(@4) - storage_live(i@9) - i@9 := const (0 : usize) - loop { - storage_live(@10) - storage_live(@11) - @11 := copy (i@9) - storage_live(@12) - storage_live(@13) - @13 := &*(s@1) with_metadata(copy (s@1.metadata)) - @12 := len<'_, u32>[{built_in impl Sized for u32}](move (@13)) - storage_dead(@13) - @10 := move (@11) < move (@12) - if move (@10) { - } - else { - break 0 - } - storage_dead(@12) - storage_dead(@11) - storage_live(@14) - storage_live(@15) - storage_live(@16) - @16 := copy (i@9) - storage_live(@24) - @24 := &*(s@1) with_metadata(copy (s@1.metadata)) - storage_live(@25) - @25 := @SliceIndexShared<'_, u32>(move (@24), copy (@16)) - @15 := copy (*(@25)) - storage_live(@17) - storage_live(@18) - @18 := copy (i@9) - storage_live(@22) - @22 := &*(s2@2) with_metadata(copy (s2@2.metadata)) - storage_live(@23) - @23 := @SliceIndexShared<'_, u32>(move (@22), copy (@18)) - @17 := copy (*(@23)) - @19 := copy (@15) panic.+ copy (@17) - @14 := move (@19) - storage_dead(@17) - storage_dead(@15) - @20 := copy (sum@3) panic.+ copy (@14) - sum@3 := move (@20) - storage_dead(@14) - storage_dead(@18) - storage_dead(@16) - @21 := copy (i@9) panic.+ const (1 : usize) - i@9 := move (@21) - storage_dead(@10) - continue 0 - } - storage_dead(@12) - storage_dead(@11) - storage_dead(@10) - @0 := copy (sum@3) - storage_dead(i@9) - storage_dead(sum@3) - return } // Full name: test_crate::f0 @@ -2063,19 +2059,17 @@ pub fn zero_slice<'_0>(@1: &'_0 mut (Slice)) @9 := copy (i@2) panic.+ const (1 : usize) i@2 := move (@9) storage_dead(@5) - continue 0 } else { - break 0 + storage_dead(@7) + storage_dead(@6) + @0 := () + storage_dead(@5) + storage_dead(len@3) + storage_dead(i@2) + return } } - storage_dead(@7) - storage_dead(@6) - @0 := () - storage_dead(@5) - storage_dead(len@3) - storage_dead(i@2) - return } // Full name: test_crate::iter_mut_slice @@ -2113,19 +2107,17 @@ pub fn iter_mut_slice<'_0>(@1: &'_0 mut (Slice)) @8 := copy (i@4) panic.+ const (1 : usize) i@4 := move (@8) storage_dead(@5) - continue 0 } else { - break 0 + storage_dead(@7) + storage_dead(@6) + @0 := () + storage_dead(@5) + storage_dead(i@4) + storage_dead(len@2) + return } } - storage_dead(@7) - storage_dead(@6) - @0 := () - storage_dead(@5) - storage_dead(i@4) - storage_dead(len@2) - return } // Full name: test_crate::sum_mut_slice @@ -2163,36 +2155,34 @@ pub fn sum_mut_slice<'_0>(@1: &'_0 mut (Slice)) -> u32 storage_dead(@7) @4 := move (@5) < move (@6) if move (@4) { + storage_dead(@6) + storage_dead(@5) + storage_live(@8) + storage_live(@9) + @9 := copy (i@2) + storage_live(@12) + @12 := &*(a@1) with_metadata(copy (a@1.metadata)) + storage_live(@13) + @13 := @SliceIndexShared<'_, u32>(move (@12), copy (@9)) + @8 := copy (*(@13)) + @10 := copy (s@3) panic.+ copy (@8) + s@3 := move (@10) + storage_dead(@8) + storage_dead(@9) + @11 := copy (i@2) panic.+ const (1 : usize) + i@2 := move (@11) + storage_dead(@4) } else { - break 0 + storage_dead(@6) + storage_dead(@5) + storage_dead(@4) + @0 := copy (s@3) + storage_dead(s@3) + storage_dead(i@2) + return } - storage_dead(@6) - storage_dead(@5) - storage_live(@8) - storage_live(@9) - @9 := copy (i@2) - storage_live(@12) - @12 := &*(a@1) with_metadata(copy (a@1.metadata)) - storage_live(@13) - @13 := @SliceIndexShared<'_, u32>(move (@12), copy (@9)) - @8 := copy (*(@13)) - @10 := copy (s@3) panic.+ copy (@8) - s@3 := move (@10) - storage_dead(@8) - storage_dead(@9) - @11 := copy (i@2) panic.+ const (1 : usize) - i@2 := move (@11) - storage_dead(@4) - continue 0 } - storage_dead(@6) - storage_dead(@5) - storage_dead(@4) - @0 := copy (s@3) - storage_dead(s@3) - storage_dead(i@2) - return } // Full name: test_crate::slice_pattern_1 @@ -2303,20 +2293,20 @@ fn slice_pattern_4<'_0>(@1: &'_0 (Slice<()>)) @4 := const (1 : usize) @5 := move (@2) == move (@4) if move (@5) { + storage_live(_named@6) + storage_live(@7) + @7 := &*(x@1) with_metadata(copy (x@1.metadata)) + storage_live(@8) + @8 := @SliceIndexShared<'_, ()>(move (@7), const (0 : usize)) + _named@6 := &*(@8) + @0 := () + storage_dead(_named@6) + return } else { @0 := () return } - storage_live(_named@6) - storage_live(@7) - @7 := &*(x@1) with_metadata(copy (x@1.metadata)) - storage_live(@8) - @8 := @SliceIndexShared<'_, ()>(move (@7), const (0 : usize)) - _named@6 := &*(@8) - @0 := () - storage_dead(_named@6) - return } diff --git a/charon/tests/ui/closures.out b/charon/tests/ui/closures.out index f2bc8214b..763a266fb 100644 --- a/charon/tests/ui/closures.out +++ b/charon/tests/ui/closures.out @@ -242,6 +242,8 @@ where match *(x@1) { Option::None => { + @0 := Option::None { } + return }, Option::Some => { storage_live(x@3) @@ -261,8 +263,6 @@ where return }, } - @0 := Option::None { } - return } // Full name: test_crate::test_map_option1 diff --git a/charon/tests/ui/comments.out b/charon/tests/ui/comments.out index 0ca18b226..172320a64 100644 --- a/charon/tests/ui/comments.out +++ b/charon/tests/ui/comments.out @@ -168,74 +168,72 @@ pub fn sum<'_0>(@1: &'_0 (Slice)) -> u32 storage_dead(@11) @8 := move (@9) < move (@10) if move (@8) { + storage_dead(@10) + storage_dead(@9) + storage_live(@12) + storage_live(@13) + // Add to running sum + @13 := copy (i@3) + storage_live(@25) + @25 := &*(s@1) with_metadata(copy (s@1.metadata)) + storage_live(@26) + @26 := @SliceIndexShared<'_, u32>(move (@25), copy (@13)) + @12 := copy (*(@26)) + @14 := copy (sum@2) panic.+ copy (@12) + sum@2 := move (@14) + storage_dead(@12) + storage_dead(@13) + // Increment `i` + @15 := copy (i@3) panic.+ const (1 : usize) + i@3 := move (@15) + // Before end of loop + storage_dead(@8) } else { - break 0 + storage_dead(@10) + storage_dead(@9) + storage_dead(@8) + storage_live(@16) + storage_live(@17) + storage_live(@18) + // Assign the result of an `if`. + @18 := copy (sum@2) + @17 := move (@18) > const (10 : u32) + if move (@17) { + storage_dead(@18) + storage_live(@19) + // sum + 100 + @19 := copy (sum@2) + @20 := copy (@19) panic.+ const (100 : u32) + @16 := move (@20) + storage_dead(@19) + } + else { + storage_dead(@18) + // let sum untouched + @16 := copy (sum@2) + } + storage_dead(@17) + sum@2 := move (@16) + storage_dead(@16) + storage_live(@21) + storage_live(@22) + storage_live(@23) + // Function call + @23 := copy (sum@2) + @24 := copy (@23) panic.+ const (2 : u32) + @22 := move (@24) + storage_dead(@23) + @21 := function_call(move (@22)) + storage_dead(@22) + storage_dead(@21) + // Return final value + @0 := copy (sum@2) + storage_dead(i@3) + storage_dead(sum@2) + return } - storage_dead(@10) - storage_dead(@9) - storage_live(@12) - storage_live(@13) - // Add to running sum - @13 := copy (i@3) - storage_live(@25) - @25 := &*(s@1) with_metadata(copy (s@1.metadata)) - storage_live(@26) - @26 := @SliceIndexShared<'_, u32>(move (@25), copy (@13)) - @12 := copy (*(@26)) - @14 := copy (sum@2) panic.+ copy (@12) - sum@2 := move (@14) - storage_dead(@12) - storage_dead(@13) - // Increment `i` - @15 := copy (i@3) panic.+ const (1 : usize) - i@3 := move (@15) - // Before end of loop - storage_dead(@8) - continue 0 } - storage_dead(@10) - storage_dead(@9) - storage_dead(@8) - storage_live(@16) - storage_live(@17) - storage_live(@18) - // Assign the result of an `if`. - @18 := copy (sum@2) - @17 := move (@18) > const (10 : u32) - if move (@17) { - storage_dead(@18) - storage_live(@19) - // sum + 100 - @19 := copy (sum@2) - @20 := copy (@19) panic.+ const (100 : u32) - @16 := move (@20) - storage_dead(@19) - } - else { - storage_dead(@18) - // let sum untouched - @16 := copy (sum@2) - } - storage_dead(@17) - sum@2 := move (@16) - storage_dead(@16) - storage_live(@21) - storage_live(@22) - storage_live(@23) - // Function call - @23 := copy (sum@2) - @24 := copy (@23) panic.+ const (2 : u32) - @22 := move (@24) - storage_dead(@23) - @21 := function_call(move (@22)) - storage_dead(@22) - storage_dead(@21) - // Return final value - @0 := copy (sum@2) - storage_dead(i@3) - storage_dead(sum@2) - return } // Full name: test_crate::Foo @@ -433,6 +431,20 @@ fn foo() @24 := copy (*(right_val@21)) @22 := move (@23) == move (@24) if move (@22) { + storage_dead(@24) + storage_dead(@23) + storage_dead(@22) + storage_dead(right_val@21) + storage_dead(left_val@20) + storage_dead(@18) + storage_dead(@16) + @0 := () + storage_dead(a@15) + storage_dead(super_long_field_name@9) + storage_dead(x@8) + storage_dead(y@2) + storage_dead(x@1) + return } else { storage_dead(@24) @@ -453,20 +465,6 @@ fn foo() @31 := Option::None { } panic(core::panicking::assert_failed) } - storage_dead(@24) - storage_dead(@23) - storage_dead(@22) - storage_dead(right_val@21) - storage_dead(left_val@20) - storage_dead(@18) - storage_dead(@16) - @0 := () - storage_dead(a@15) - storage_dead(super_long_field_name@9) - storage_dead(x@8) - storage_dead(y@2) - storage_dead(x@1) - return } // Full name: test_crate::CONSTANT diff --git a/charon/tests/ui/control-flow/lazy-boolean-op-in-if.out b/charon/tests/ui/control-flow/lazy-boolean-op-in-if.out new file mode 100644 index 000000000..c1f38137b --- /dev/null +++ b/charon/tests/ui/control-flow/lazy-boolean-op-in-if.out @@ -0,0 +1,99 @@ +# Final LLBC before serialization: + +fn UNIT_METADATA() +{ + let @0: (); // return + + @0 := () + return +} + +const UNIT_METADATA: () = @Fun0() + +// Full name: test_crate::foo +fn foo() -> bool +{ + let @0: bool; // return + + @0 := const (true) + return +} + +// Full name: test_crate::bar +fn bar() -> bool +{ + let @0: bool; // return + + @0 := const (false) + return +} + +// Full name: test_crate::do_something +fn do_something() +{ + let @0: (); // return + + @0 := () + @0 := () + return +} + +// Full name: test_crate::do_something_else +fn do_something_else() +{ + let @0: (); // return + + @0 := () + @0 := () + return +} + +// Full name: test_crate::do_something_at_the_end +fn do_something_at_the_end() +{ + let @0: (); // return + + @0 := () + @0 := () + return +} + +// Full name: test_crate::main +fn main() +{ + let @0: (); // return + let @1: (); // anonymous local + let @2: bool; // anonymous local + let @3: bool; // anonymous local + + @0 := () + storage_live(@1) + storage_live(@2) + // `&&` inside `if` is treated specially by Rust: must like for `if let && let`, it is + // considered as directly being control-flow, instead of computing a boolean first. + @2 := foo() + loop { + if move (@2) { + storage_live(@3) + @3 := bar() + if move (@3) { + @1 := do_something() + break 0 + } + else { + } + } + else { + } + @1 := do_something_else() + break 0 + } + storage_dead(@3) + storage_dead(@2) + storage_dead(@1) + @0 := do_something_at_the_end() + return +} + + + diff --git a/charon/tests/ui/control-flow/lazy-boolean-op-in-if.rs b/charon/tests/ui/control-flow/lazy-boolean-op-in-if.rs new file mode 100644 index 000000000..54a7e18b0 --- /dev/null +++ b/charon/tests/ui/control-flow/lazy-boolean-op-in-if.rs @@ -0,0 +1,21 @@ +fn foo() -> bool { + true +} +fn bar() -> bool { + false +} + +fn do_something() {} +fn do_something_else() {} +fn do_something_at_the_end() {} + +fn main() { + // `&&` inside `if` is treated specially by Rust: must like for `if let && let`, it is + // considered as directly being control-flow, instead of computing a boolean first. + if foo() && bar() { + do_something() + } else { + do_something_else() + } + do_something_at_the_end() +} diff --git a/charon/tests/ui/control-flow/loop-break.out b/charon/tests/ui/control-flow/loop-break.out new file mode 100644 index 000000000..d2964ae7f --- /dev/null +++ b/charon/tests/ui/control-flow/loop-break.out @@ -0,0 +1,105 @@ +# Final LLBC before serialization: + +fn UNIT_METADATA() +{ + let @0: (); // return + + @0 := () + return +} + +const UNIT_METADATA: () = @Fun0() + +// Full name: test_crate::foo +fn foo() -> bool +{ + let @0: bool; // return + + @0 := const (false) + return +} + +// Full name: test_crate::bar +fn bar() -> bool +{ + let @0: bool; // return + + @0 := const (true) + return +} + +// Full name: test_crate::do_something +fn do_something() +{ + let @0: (); // return + + @0 := () + @0 := () + return +} + +// Full name: test_crate::do_something_at_the_end +fn do_something_at_the_end() +{ + let @0: (); // return + + @0 := () + @0 := () + return +} + +// Full name: test_crate::main +fn main() +{ + let @0: (); // return + let @1: bool; // anonymous local + let @2: (); // anonymous local + let @3: bool; // anonymous local + let @4: bool; // anonymous local + + @0 := () + storage_live(@1) + // Needed a few convolutions to make it emit a `break` instead of moving the `return` + // inside the loop. + @1 := foo() + loop { + loop { + if move (@1) { + } + else { + break 1 + } + break 0 + } + loop { + storage_live(@2) + @2 := do_something() + storage_dead(@2) + storage_live(@3) + @3 := foo() + if move (@3) { + } + else { + storage_live(@4) + @4 := bar() + if move (@4) { + } + else { + storage_dead(@4) + storage_dead(@3) + continue 0 + } + } + storage_dead(@4) + storage_dead(@3) + break 1 + } + break 0 + } + storage_dead(@1) + @0 := do_something_at_the_end() + return +} + + + diff --git a/charon/tests/ui/control-flow/loop-break.rs b/charon/tests/ui/control-flow/loop-break.rs new file mode 100644 index 000000000..1a4f43a55 --- /dev/null +++ b/charon/tests/ui/control-flow/loop-break.rs @@ -0,0 +1,22 @@ +fn foo() -> bool { + false +} +fn bar() -> bool { + true +} +fn do_something() {} +fn do_something_at_the_end() {} + +fn main() { + // Needed a few convolutions to make it emit a `break` instead of moving the `return` + // inside the loop. + if foo() { + loop { + do_something(); + if foo() || bar() { + break; + } + } + } + do_something_at_the_end() +} diff --git a/charon/tests/ui/control-flow/simple-fallthrough.out b/charon/tests/ui/control-flow/simple-fallthrough.out new file mode 100644 index 000000000..ce5ba3912 --- /dev/null +++ b/charon/tests/ui/control-flow/simple-fallthrough.out @@ -0,0 +1,118 @@ +# Final LLBC before serialization: + +// Full name: core::marker::MetaSized +#[lang_item("meta_sized")] +pub trait MetaSized + +// Full name: core::marker::Sized +#[lang_item("sized")] +pub trait Sized +{ + parent_clause0 : [@TraitClause0]: MetaSized + non-dyn-compatible +} + +// Full name: core::option::Option +#[lang_item("Option")] +pub enum Option +where + [@TraitClause0]: Sized, +{ + None, + Some(T), +} + +fn UNIT_METADATA() +{ + let @0: (); // return + + @0 := () + return +} + +const UNIT_METADATA: () = @Fun0() + +// Full name: test_crate::do_something +fn do_something() +{ + let @0: (); // return + + @0 := () + @0 := () + return +} + +// Full name: test_crate::do_something_else +fn do_something_else() +{ + let @0: (); // return + + @0 := () + @0 := () + return +} + +// Full name: test_crate::do_something_at_the_end +fn do_something_at_the_end() +{ + let @0: (); // return + + @0 := () + @0 := () + return +} + +// Full name: test_crate::foo +fn foo(@1: Option[{built_in impl Sized for u32}]) +{ + let @0: (); // return + let opt@1: Option[{built_in impl Sized for u32}]; // arg #1 + let @2: (); // anonymous local + let @3: &'_ (Option[{built_in impl Sized for u32}]); // anonymous local + let x@4: u32; // local + let x@5: &'_ (u32); // local + let @6: bool; // anonymous local + let @7: u32; // anonymous local + + loop { + storage_live(@3) + @0 := () + storage_live(@2) + match opt@1 { + Option::Some => { + storage_live(x@5) + x@5 := &(opt@1 as variant Option::Some).0 + @3 := &shallow opt@1 + storage_live(@6) + storage_live(@7) + @7 := copy (*(x@5)) + @6 := move (@7) >= const (42 : u32) + if move (@6) { + storage_dead(@7) + storage_dead(@6) + storage_live(x@4) + x@4 := copy ((opt@1 as variant Option::Some).0) + @2 := do_something() + storage_dead(x@4) + storage_dead(x@5) + break 0 + } + else { + storage_dead(@7) + storage_dead(@6) + storage_dead(x@5) + } + }, + _ => { + }, + } + @2 := do_something_else() + break 0 + } + storage_dead(@2) + @0 := do_something_at_the_end() + return +} + + + diff --git a/charon/tests/ui/control-flow/simple-fallthrough.rs b/charon/tests/ui/control-flow/simple-fallthrough.rs new file mode 100644 index 000000000..3ded8aa79 --- /dev/null +++ b/charon/tests/ui/control-flow/simple-fallthrough.rs @@ -0,0 +1,13 @@ +fn do_something() {} +fn do_something_else() {} +fn do_something_at_the_end() {} + +// This has a cfg in the form of a diamond with a diagonal: can't be mapped to simple nested `if`s. +// This may require duplicating a node or adding intermediate branching flags. +fn foo(opt: Option) { + match opt { + Some(x) if x >= 42 => do_something(), + _ => do_something_else(), + } + do_something_at_the_end() +} diff --git a/charon/tests/ui/demo.out b/charon/tests/ui/demo.out index eaae0c026..ea3a65aa0 100644 --- a/charon/tests/ui/demo.out +++ b/charon/tests/ui/demo.out @@ -209,44 +209,44 @@ where storage_live(@11) match *(l@1) { CList::CCons => { + storage_live(x@3) + x@3 := &(*(l@1) as variant CList::CCons).0 + storage_live(tl@4) + tl@4 := &(*(l@1) as variant CList::CCons).1 + storage_live(@5) + storage_live(@6) + @6 := copy (i@2) + @5 := move (@6) == const (0 : u32) + if move (@5) { + storage_dead(@6) + @0 := &*(x@3) + } + else { + storage_dead(@6) + storage_live(@7) + storage_live(@8) + @8 := &*(*(tl@4)) + storage_live(@9) + storage_live(@10) + @10 := copy (i@2) + @11 := copy (@10) panic.- const (1 : u32) + @9 := move (@11) + storage_dead(@10) + @7 := list_nth<'_, T>[@TraitClause0](move (@8), move (@9)) + @0 := &*(@7) + storage_dead(@9) + storage_dead(@8) + storage_dead(@7) + } + storage_dead(@5) + storage_dead(tl@4) + storage_dead(x@3) + return }, CList::CNil => { panic(core::panicking::panic) }, } - storage_live(x@3) - x@3 := &(*(l@1) as variant CList::CCons).0 - storage_live(tl@4) - tl@4 := &(*(l@1) as variant CList::CCons).1 - storage_live(@5) - storage_live(@6) - @6 := copy (i@2) - @5 := move (@6) == const (0 : u32) - if move (@5) { - storage_dead(@6) - @0 := &*(x@3) - } - else { - storage_dead(@6) - storage_live(@7) - storage_live(@8) - @8 := &*(*(tl@4)) - storage_live(@9) - storage_live(@10) - @10 := copy (i@2) - @11 := copy (@10) panic.- const (1 : u32) - @9 := move (@11) - storage_dead(@10) - @7 := list_nth<'_, T>[@TraitClause0](move (@8), move (@9)) - @0 := &*(@7) - storage_dead(@9) - storage_dead(@8) - storage_dead(@7) - } - storage_dead(@5) - storage_dead(tl@4) - storage_dead(x@3) - return } // Full name: test_crate::list_nth_mut @@ -277,57 +277,57 @@ where storage_live(@4) match *(l@1) { CList::CCons => { + storage_live(x@5) + x@5 := &mut (*(l@1) as variant CList::CCons).0 + storage_live(tl@6) + tl@6 := &mut (*(l@1) as variant CList::CCons).1 + storage_live(@7) + storage_live(@8) + storage_live(@9) + storage_live(@10) + @10 := copy (i@2) + @9 := move (@10) == const (0 : u32) + if move (@9) { + storage_dead(@10) + storage_live(@11) + @11 := &mut *(x@5) + @8 := &mut *(@11) + storage_dead(@11) + } + else { + storage_dead(@10) + storage_live(@12) + storage_live(@13) + @13 := &two-phase-mut *(*(tl@6)) + storage_live(@14) + storage_live(@15) + @15 := copy (i@2) + @16 := copy (@15) panic.- const (1 : u32) + @14 := move (@16) + storage_dead(@15) + @12 := list_nth_mut<'_, T>[@TraitClause0](move (@13), move (@14)) + @8 := &mut *(@12) + storage_dead(@14) + storage_dead(@13) + storage_dead(@12) + } + @7 := &mut *(@8) + storage_dead(@9) + @4 := &mut *(@7) + storage_dead(@8) + storage_dead(@7) + storage_dead(tl@6) + storage_dead(x@5) + @3 := &mut *(@4) + @0 := &mut *(@3) + storage_dead(@4) + storage_dead(@3) + return }, CList::CNil => { panic(core::panicking::panic) }, } - storage_live(x@5) - x@5 := &mut (*(l@1) as variant CList::CCons).0 - storage_live(tl@6) - tl@6 := &mut (*(l@1) as variant CList::CCons).1 - storage_live(@7) - storage_live(@8) - storage_live(@9) - storage_live(@10) - @10 := copy (i@2) - @9 := move (@10) == const (0 : u32) - if move (@9) { - storage_dead(@10) - storage_live(@11) - @11 := &mut *(x@5) - @8 := &mut *(@11) - storage_dead(@11) - } - else { - storage_dead(@10) - storage_live(@12) - storage_live(@13) - @13 := &two-phase-mut *(*(tl@6)) - storage_live(@14) - storage_live(@15) - @15 := copy (i@2) - @16 := copy (@15) panic.- const (1 : u32) - @14 := move (@16) - storage_dead(@15) - @12 := list_nth_mut<'_, T>[@TraitClause0](move (@13), move (@14)) - @8 := &mut *(@12) - storage_dead(@14) - storage_dead(@13) - storage_dead(@12) - } - @7 := &mut *(@8) - storage_dead(@9) - @4 := &mut *(@7) - storage_dead(@8) - storage_dead(@7) - storage_dead(tl@6) - storage_dead(x@5) - @3 := &mut *(@4) - @0 := &mut *(@3) - storage_dead(@4) - storage_dead(@3) - return } // Full name: test_crate::list_nth_mut1 @@ -358,6 +358,12 @@ where @6 := copy (i@2) @5 := move (@6) == const (0 : u32) if move (@5) { + storage_dead(@6) + @0 := &mut *(x@3) + storage_dead(@5) + storage_dead(tl@4) + storage_dead(x@3) + return } else { storage_dead(@6) @@ -370,14 +376,7 @@ where storage_dead(@8) storage_dead(tl@4) storage_dead(x@3) - continue 0 } - storage_dead(@6) - @0 := &mut *(x@3) - storage_dead(@5) - storage_dead(tl@4) - storage_dead(x@3) - return }, _ => { panic(core::panicking::panic) diff --git a/charon/tests/ui/gosim-demo.out b/charon/tests/ui/gosim-demo.out index 8325a73c4..51b055550 100644 --- a/charon/tests/ui/gosim-demo.out +++ b/charon/tests/ui/gosim-demo.out @@ -578,7 +578,12 @@ where storage_dead(@6) match @5 { Option::None => { - break 0 + @0 := () + storage_dead(@7) + storage_dead(@5) + storage_dead(iter@4) + storage_dead(@2) + return }, Option::Some => { storage_live(x@8) @@ -624,16 +629,9 @@ where storage_dead(x@8) storage_dead(@7) storage_dead(@5) - continue 0 }, } } - @0 := () - storage_dead(@7) - storage_dead(@5) - storage_dead(iter@4) - storage_dead(@2) - return } // Full name: test_crate::main diff --git a/charon/tests/ui/issue-114-opaque-bodies.out b/charon/tests/ui/issue-114-opaque-bodies.out index 6e399ca7f..f3a2352aa 100644 --- a/charon/tests/ui/issue-114-opaque-bodies.out +++ b/charon/tests/ui/issue-114-opaque-bodies.out @@ -41,17 +41,17 @@ where let @3: T; // anonymous local if copy (self@1) { + storage_live(@3) + @3 := move (t@2) + @0 := Option::Some { 0: move (@3) } + storage_dead(@3) + return } else { @0 := Option::None { } drop[{built_in impl Destruct for T}] t@2 return } - storage_live(@3) - @3 := move (t@2) - @0 := Option::Some { 0: move (@3) } - storage_dead(@3) - return } // Full name: core::cmp::PartialEq diff --git a/charon/tests/ui/issue-297-cfg.out b/charon/tests/ui/issue-297-cfg.out index 3e800a1fd..474d7d5fe 100644 --- a/charon/tests/ui/issue-297-cfg.out +++ b/charon/tests/ui/issue-297-cfg.out @@ -478,47 +478,51 @@ fn f1<'_0>(@1: &'_0 (Slice)) -> usize let @13: &'_ (Slice); // anonymous local let @14: &'_ (u8); // anonymous local - storage_live(@9) - storage_live(@10) - storage_live(sampled@2) - sampled@2 := const (0 : usize) - storage_live(@3) - storage_live(@4) - storage_live(@5) - @5 := const (0 : usize) - storage_live(@13) - @13 := &*(a@1) with_metadata(copy (a@1.metadata)) - storage_live(@14) - @14 := @SliceIndexShared<'_, u8>(move (@13), copy (@5)) - @4 := copy (*(@14)) - @3 := move (@4) < const (42 : u8) - if move (@3) { - storage_dead(@5) - storage_dead(@4) - storage_live(@6) - storage_live(@7) - storage_live(@8) - @8 := const (1 : usize) - storage_live(@11) - @11 := &*(a@1) with_metadata(copy (a@1.metadata)) - storage_live(@12) - @12 := @SliceIndexShared<'_, u8>(move (@11), copy (@8)) - @7 := copy (*(@12)) - @6 := move (@7) < const (16 : u8) - if move (@6) { - storage_dead(@8) - storage_dead(@7) - @9 := copy (sampled@2) panic.+ const (100 : usize) - sampled@2 := move (@9) + loop { + storage_live(@9) + storage_live(@10) + storage_live(sampled@2) + sampled@2 := const (0 : usize) + storage_live(@3) + storage_live(@4) + storage_live(@5) + @5 := const (0 : usize) + storage_live(@13) + @13 := &*(a@1) with_metadata(copy (a@1.metadata)) + storage_live(@14) + @14 := @SliceIndexShared<'_, u8>(move (@13), copy (@5)) + @4 := copy (*(@14)) + @3 := move (@4) < const (42 : u8) + if move (@3) { + storage_dead(@5) + storage_dead(@4) + storage_live(@6) + storage_live(@7) + storage_live(@8) + @8 := const (1 : usize) + storage_live(@11) + @11 := &*(a@1) with_metadata(copy (a@1.metadata)) + storage_live(@12) + @12 := @SliceIndexShared<'_, u8>(move (@11), copy (@8)) + @7 := copy (*(@12)) + @6 := move (@7) < const (16 : u8) + if move (@6) { + storage_dead(@8) + storage_dead(@7) + @9 := copy (sampled@2) panic.+ const (100 : usize) + sampled@2 := move (@9) + break 0 + } + else { + storage_dead(@8) + storage_dead(@7) + } } else { - storage_dead(@8) - storage_dead(@7) + storage_dead(@5) + storage_dead(@4) } - } - else { - storage_dead(@5) - storage_dead(@4) + break 0 } storage_dead(@6) storage_dead(@3) @@ -591,14 +595,14 @@ fn f2<'_0, '_1>(@1: &'_0 (Slice), @2: &'_1 mut (Slice)) -> usize let @44: usize; // anonymous local let @45: &'_ mut (Slice); // anonymous local let @46: &'_ mut (i16); // anonymous local - let @47: &'_ mut (Slice); // anonymous local - let @48: &'_ mut (i16); // anonymous local + let @47: &'_ (Slice); // anonymous local + let @48: &'_ (u8); // anonymous local let @49: &'_ (Slice); // anonymous local let @50: &'_ (u8); // anonymous local let @51: &'_ (Slice); // anonymous local let @52: &'_ (u8); // anonymous local - let @53: &'_ (Slice); // anonymous local - let @54: &'_ (u8); // anonymous local + let @53: &'_ mut (Slice); // anonymous local + let @54: &'_ mut (i16); // anonymous local storage_live(@37) storage_live(@44) @@ -624,142 +628,156 @@ fn f2<'_0, '_1>(@1: &'_0 (Slice), @2: &'_1 mut (Slice)) -> usize storage_dead(@9) match @8 { Option::None => { - break 0 + storage_dead(@10) + storage_dead(@8) + storage_dead(iter@7) + storage_dead(@4) + @0 := copy (sampled@3) + storage_dead(sampled@3) + return }, Option::Some => { - storage_live(bytes@11) - bytes@11 := copy ((@8 as variant Option::Some).0) - storage_live(b1@12) - storage_live(@13) - storage_live(@14) - @14 := const (0 : usize) - storage_live(@53) - @53 := &*(bytes@11) with_metadata(copy (bytes@11.metadata)) - storage_live(@54) - @54 := @SliceIndexShared<'_, u8>(move (@53), copy (@14)) - @13 := copy (*(@54)) - b1@12 := cast(move (@13)) - storage_dead(@13) - storage_dead(@14) - storage_live(b2@15) - storage_live(@16) - storage_live(@17) - @17 := const (1 : usize) - storage_live(@51) - @51 := &*(bytes@11) with_metadata(copy (bytes@11.metadata)) - storage_live(@52) - @52 := @SliceIndexShared<'_, u8>(move (@51), copy (@17)) - @16 := copy (*(@52)) - b2@15 := cast(move (@16)) - storage_dead(@16) - storage_dead(@17) - storage_live(b3@18) - storage_live(@19) - storage_live(@20) - @20 := const (2 : usize) - storage_live(@49) - @49 := &*(bytes@11) with_metadata(copy (bytes@11.metadata)) - storage_live(@50) - @50 := @SliceIndexShared<'_, u8>(move (@49), copy (@20)) - @19 := copy (*(@50)) - b3@18 := cast(move (@19)) - storage_dead(@19) - storage_dead(@20) - storage_live(d1@21) - storage_live(@22) - storage_live(@23) - storage_live(@24) - @24 := copy (b2@15) - @23 := move (@24) & const (15 : i16) - storage_dead(@24) - @22 := move (@23) panic.<< const (8 : i32) - storage_dead(@23) - storage_live(@25) - @25 := copy (b1@12) - d1@21 := move (@22) | move (@25) - storage_dead(@25) - storage_dead(@22) - storage_live(d2@26) - storage_live(@27) - storage_live(@28) - @28 := copy (b3@18) - @27 := move (@28) panic.<< const (4 : i32) - storage_dead(@28) - storage_live(@29) - storage_live(@30) - @30 := copy (b2@15) - @29 := move (@30) panic.>> const (4 : i32) - storage_dead(@30) - d2@26 := move (@27) | move (@29) - storage_dead(@29) - storage_dead(@27) - storage_live(@31) - storage_live(@32) - @32 := copy (d1@21) - @31 := move (@32) < copy (FIELD_MODULUS) - if move (@31) { - storage_dead(@32) - storage_live(@33) - storage_live(@34) - @34 := copy (sampled@3) - @33 := move (@34) < const (16 : usize) - if move (@33) { - storage_dead(@34) - storage_live(@35) - @35 := copy (d1@21) - storage_live(@36) - @36 := copy (sampled@3) - storage_live(@45) - @45 := &mut *(result@2) with_metadata(copy (result@2.metadata)) - storage_live(@46) - @46 := @SliceIndexMut<'_, i16>(move (@45), copy (@36)) - *(@46) := move (@35) - storage_dead(@35) - storage_dead(@36) - @37 := copy (sampled@3) panic.+ const (1 : usize) - sampled@3 := move (@37) + loop { + storage_live(bytes@11) + bytes@11 := copy ((@8 as variant Option::Some).0) + storage_live(b1@12) + storage_live(@13) + storage_live(@14) + @14 := const (0 : usize) + storage_live(@51) + @51 := &*(bytes@11) with_metadata(copy (bytes@11.metadata)) + storage_live(@52) + @52 := @SliceIndexShared<'_, u8>(move (@51), copy (@14)) + @13 := copy (*(@52)) + b1@12 := cast(move (@13)) + storage_dead(@13) + storage_dead(@14) + storage_live(b2@15) + storage_live(@16) + storage_live(@17) + @17 := const (1 : usize) + storage_live(@49) + @49 := &*(bytes@11) with_metadata(copy (bytes@11.metadata)) + storage_live(@50) + @50 := @SliceIndexShared<'_, u8>(move (@49), copy (@17)) + @16 := copy (*(@50)) + b2@15 := cast(move (@16)) + storage_dead(@16) + storage_dead(@17) + storage_live(b3@18) + storage_live(@19) + storage_live(@20) + @20 := const (2 : usize) + storage_live(@47) + @47 := &*(bytes@11) with_metadata(copy (bytes@11.metadata)) + storage_live(@48) + @48 := @SliceIndexShared<'_, u8>(move (@47), copy (@20)) + @19 := copy (*(@48)) + b3@18 := cast(move (@19)) + storage_dead(@19) + storage_dead(@20) + storage_live(d1@21) + storage_live(@22) + storage_live(@23) + storage_live(@24) + @24 := copy (b2@15) + @23 := move (@24) & const (15 : i16) + storage_dead(@24) + @22 := move (@23) panic.<< const (8 : i32) + storage_dead(@23) + storage_live(@25) + @25 := copy (b1@12) + d1@21 := move (@22) | move (@25) + storage_dead(@25) + storage_dead(@22) + storage_live(d2@26) + storage_live(@27) + storage_live(@28) + @28 := copy (b3@18) + @27 := move (@28) panic.<< const (4 : i32) + storage_dead(@28) + storage_live(@29) + storage_live(@30) + @30 := copy (b2@15) + @29 := move (@30) panic.>> const (4 : i32) + storage_dead(@30) + d2@26 := move (@27) | move (@29) + storage_dead(@29) + storage_dead(@27) + storage_live(@31) + storage_live(@32) + @32 := copy (d1@21) + @31 := move (@32) < copy (FIELD_MODULUS) + if move (@31) { + storage_dead(@32) + storage_live(@33) + storage_live(@34) + @34 := copy (sampled@3) + @33 := move (@34) < const (16 : usize) + if move (@33) { + storage_dead(@34) + storage_live(@35) + @35 := copy (d1@21) + storage_live(@36) + @36 := copy (sampled@3) + storage_live(@45) + @45 := &mut *(result@2) with_metadata(copy (result@2.metadata)) + storage_live(@46) + @46 := @SliceIndexMut<'_, i16>(move (@45), copy (@36)) + *(@46) := move (@35) + storage_dead(@35) + storage_dead(@36) + @37 := copy (sampled@3) panic.+ const (1 : usize) + sampled@3 := move (@37) + break 0 + } + else { + storage_dead(@34) + } } else { - storage_dead(@34) + storage_dead(@32) } + break 0 } - else { - storage_dead(@32) - } - storage_dead(@33) - storage_dead(@31) - storage_live(@38) - storage_live(@39) - @39 := copy (d2@26) - @38 := move (@39) < copy (FIELD_MODULUS) - if move (@38) { - storage_dead(@39) - storage_live(@40) - storage_live(@41) - @41 := copy (sampled@3) - @40 := move (@41) < const (16 : usize) - if move (@40) { - storage_dead(@41) - storage_live(@42) - @42 := copy (d2@26) - storage_live(@43) - @43 := copy (sampled@3) - storage_live(@47) - @47 := &mut *(result@2) with_metadata(copy (result@2.metadata)) - storage_live(@48) - @48 := @SliceIndexMut<'_, i16>(move (@47), copy (@43)) - *(@48) := move (@42) - storage_dead(@42) - storage_dead(@43) - @44 := copy (sampled@3) panic.+ const (1 : usize) - sampled@3 := move (@44) + loop { + storage_dead(@33) + storage_dead(@31) + storage_live(@38) + storage_live(@39) + @39 := copy (d2@26) + @38 := move (@39) < copy (FIELD_MODULUS) + if move (@38) { + storage_dead(@39) + storage_live(@40) + storage_live(@41) + @41 := copy (sampled@3) + @40 := move (@41) < const (16 : usize) + if move (@40) { + storage_dead(@41) + storage_live(@42) + @42 := copy (d2@26) + storage_live(@43) + @43 := copy (sampled@3) + storage_live(@53) + @53 := &mut *(result@2) with_metadata(copy (result@2.metadata)) + storage_live(@54) + @54 := @SliceIndexMut<'_, i16>(move (@53), copy (@43)) + *(@54) := move (@42) + storage_dead(@42) + storage_dead(@43) + @44 := copy (sampled@3) panic.+ const (1 : usize) + sampled@3 := move (@44) + break 0 + } + else { + storage_dead(@41) + } } else { - storage_dead(@41) + storage_dead(@39) } - } - else { - storage_dead(@39) + break 0 } storage_dead(@40) storage_dead(@38) @@ -771,17 +789,9 @@ fn f2<'_0, '_1>(@1: &'_0 (Slice), @2: &'_1 mut (Slice)) -> usize storage_dead(bytes@11) storage_dead(@10) storage_dead(@8) - continue 0 }, } } - storage_dead(@10) - storage_dead(@8) - storage_dead(iter@7) - storage_dead(@4) - @0 := copy (sampled@3) - storage_dead(sampled@3) - return } diff --git a/charon/tests/ui/issue-320-slice-pattern.out b/charon/tests/ui/issue-320-slice-pattern.out index bb76df738..2262c2173 100644 --- a/charon/tests/ui/issue-320-slice-pattern.out +++ b/charon/tests/ui/issue-320-slice-pattern.out @@ -232,20 +232,20 @@ fn slice_pat4<'_0>(@1: &'_0 (Slice)) @4 := const (1 : usize) @5 := move (@2) == move (@4) if move (@5) { + storage_live(_y@6) + storage_live(@7) + @7 := &*(x@1) with_metadata(copy (x@1.metadata)) + storage_live(@8) + @8 := @SliceIndexShared<'_, u32>(move (@7), const (0 : usize)) + _y@6 := &*(@8) + @0 := () + storage_dead(_y@6) + return } else { @0 := () return } - storage_live(_y@6) - storage_live(@7) - @7 := &*(x@1) with_metadata(copy (x@1.metadata)) - storage_live(@8) - @8 := @SliceIndexShared<'_, u32>(move (@7), const (0 : usize)) - _y@6 := &*(@8) - @0 := () - storage_dead(_y@6) - return } // Full name: test_crate::Unsized @@ -279,20 +279,20 @@ fn slice_pat5<'_0>(@1: &'_0 (Unsized)) @5 := const (1 : usize) @6 := move (@2) == move (@5) if move (@6) { + storage_live(_y@7) + storage_live(@8) + @8 := &(*(x@1)).0 with_metadata(copy (x@1.metadata)) + storage_live(@9) + @9 := @SliceIndexShared<'_, u32>(move (@8), const (0 : usize)) + _y@7 := copy (*(@9)) + @0 := () + storage_dead(_y@7) + return } else { @0 := () return } - storage_live(_y@7) - storage_live(@8) - @8 := &(*(x@1)).0 with_metadata(copy (x@1.metadata)) - storage_live(@9) - @9 := @SliceIndexShared<'_, u32>(move (@8), const (0 : usize)) - _y@7 := copy (*(@9)) - @0 := () - storage_dead(_y@7) - return } diff --git a/charon/tests/ui/issue-45-misc.out b/charon/tests/ui/issue-45-misc.out index 2fc68c7b6..ab2405fc9 100644 --- a/charon/tests/ui/issue-45-misc.out +++ b/charon/tests/ui/issue-45-misc.out @@ -689,7 +689,12 @@ fn cbd(@1: Array) storage_dead(@6) match @5 { Option::None => { - break 0 + @0 := () + storage_dead(@7) + storage_dead(@5) + storage_dead(iter@4) + storage_dead(@2) + return }, Option::Some => { storage_live(i@8) @@ -708,16 +713,9 @@ fn cbd(@1: Array) storage_dead(i@8) storage_dead(@7) storage_dead(@5) - continue 0 }, } } - @0 := () - storage_dead(@7) - storage_dead(@5) - storage_dead(iter@4) - storage_dead(@2) - return } // Full name: test_crate::select @@ -780,6 +778,14 @@ fn select<'_0, '_1>(@1: &'_0 (Slice), @2: &'_1 (Slice)) @15 := copy (*(right_val@12)) @13 := move (@14) == move (@15) if move (@13) { + storage_dead(@15) + storage_dead(@14) + storage_dead(@13) + storage_dead(right_val@12) + storage_dead(left_val@11) + storage_dead(@9) + storage_dead(@6) + storage_dead(@4) } else { storage_dead(@15) @@ -800,14 +806,6 @@ fn select<'_0, '_1>(@1: &'_0 (Slice), @2: &'_1 (Slice)) @22 := Option::None { } panic(core::panicking::assert_failed) } - storage_dead(@15) - storage_dead(@14) - storage_dead(@13) - storage_dead(right_val@12) - storage_dead(left_val@11) - storage_dead(@9) - storage_dead(@6) - storage_dead(@4) } else { } diff --git a/charon/tests/ui/issue-507-cfg.out b/charon/tests/ui/issue-507-cfg.out index b09708e0f..9beeba8e2 100644 --- a/charon/tests/ui/issue-507-cfg.out +++ b/charon/tests/ui/issue-507-cfg.out @@ -69,29 +69,36 @@ fn f1<'_0>(@1: &'_0 (Array)) let @10: i32; // anonymous local let x@11: u8; // local - @0 := () - storage_live(previous_true_hints_seen@2) - previous_true_hints_seen@2 := const (0 : usize) - storage_live(i@3) - i@3 := const (0 : i32) + loop { + @0 := () + storage_live(previous_true_hints_seen@2) + previous_true_hints_seen@2 := const (0 : usize) + storage_live(i@3) + i@3 := const (0 : i32) + break 0 + } loop { storage_live(@4) storage_live(@5) @5 := copy (i@3) @4 := move (@5) < const (1 : i32) if move (@4) { - storage_dead(@5) - storage_live(@6) - @6 := const (0 : i32) < const (1 : i32) - if move (@6) { - } - else { - storage_live(@7) - @7 := const (1 : i32) > const (1 : i32) - if move (@7) { + loop { + storage_dead(@5) + storage_live(@6) + @6 := const (0 : i32) < const (1 : i32) + if move (@6) { } else { + storage_live(@7) + @7 := const (1 : i32) > const (1 : i32) + if move (@7) { + } + else { + break 0 + } } + break 0 } storage_dead(@7) storage_dead(@6) @@ -108,28 +115,25 @@ fn f1<'_0>(@1: &'_0 (Array)) x@11 := copy (CONST) storage_dead(x@11) storage_dead(@9) - continue 0 } else { - break 0 + storage_dead(@10) + storage_dead(@9) + storage_dead(j@8) + storage_dead(@4) + continue 1 } } - storage_dead(@10) - storage_dead(@9) - storage_dead(j@8) - storage_dead(@4) - continue 0 } else { - break 0 + storage_dead(@5) + @0 := () + storage_dead(@4) + storage_dead(i@3) + storage_dead(previous_true_hints_seen@2) + return } } - storage_dead(@5) - @0 := () - storage_dead(@4) - storage_dead(i@3) - storage_dead(previous_true_hints_seen@2) - return } diff --git a/charon/tests/ui/iterator.out b/charon/tests/ui/iterator.out index 71a7aee3e..9cb8e23ce 100644 --- a/charon/tests/ui/iterator.out +++ b/charon/tests/ui/iterator.out @@ -5255,7 +5255,182 @@ fn main() storage_dead(@8) match @7 { Option::None => { - break 0 + storage_dead(@9) + storage_dead(@7) + drop[{impl Destruct for IntoIter[@TraitClause0]}[{built_in impl Sized for i32}]] iter@6 + storage_dead(iter@6) + drop[{impl Destruct for IntoIter[@TraitClause0]}[{built_in impl Sized for i32}]] @3 + storage_dead(@3) + storage_live(@13) + storage_live(@14) + storage_live(@15) + storage_live(@16) + @16 := &a@1 + @15 := @ArrayToSliceShared<'_, i32, 7 : usize>(move (@16)) + storage_dead(@16) + @14 := iter<'_, i32>[{built_in impl Sized for i32}](move (@15)) + storage_dead(@15) + @13 := {impl IntoIterator for I}::into_iter[{built_in impl Sized for i32}]>[{built_in impl Sized for Iter<'_, i32>[{built_in impl Sized for i32}]}, {impl Iterator for Iter<'a, T>[@TraitClause0]}<'_, i32>[{built_in impl Sized for i32}]](move (@14)) + storage_dead(@14) + storage_live(iter@17) + iter@17 := move (@13) + loop { + storage_live(@18) + storage_live(@19) + storage_live(@20) + @20 := &mut iter@17 + @19 := &two-phase-mut *(@20) + @18 := {impl Iterator for Iter<'a, T>[@TraitClause0]}::next<'_, '_, i32>[{built_in impl Sized for i32}](move (@19)) + storage_dead(@19) + match @18 { + Option::None => { + storage_dead(@20) + storage_dead(@18) + storage_dead(iter@17) + storage_dead(@13) + storage_live(@25) + storage_live(@26) + storage_live(@27) + storage_live(@28) + @28 := &a@1 + @27 := @ArrayToSliceShared<'_, i32, 7 : usize>(move (@28)) + storage_dead(@28) + @26 := chunks<'_, i32>[{built_in impl Sized for i32}](move (@27), const (2 : usize)) + storage_dead(@27) + @25 := {impl IntoIterator for I}::into_iter[{built_in impl Sized for i32}]>[{built_in impl Sized for Chunks<'_, i32>[{built_in impl Sized for i32}]}, {impl Iterator for Chunks<'a, T>[@TraitClause0]}<'_, i32>[{built_in impl Sized for i32}]](move (@26)) + storage_dead(@26) + storage_live(iter@29) + iter@29 := move (@25) + loop { + storage_live(@30) + storage_live(@31) + storage_live(@32) + @32 := &mut iter@29 + @31 := &two-phase-mut *(@32) + @30 := {impl Iterator for Chunks<'a, T>[@TraitClause0]}::next<'_, '_, i32>[{built_in impl Sized for i32}](move (@31)) + storage_dead(@31) + match @30 { + Option::None => { + storage_dead(@32) + storage_dead(@30) + storage_dead(iter@29) + storage_dead(@25) + storage_live(@34) + storage_live(@35) + storage_live(@36) + storage_live(@37) + @37 := &a@1 + @36 := @ArrayToSliceShared<'_, i32, 7 : usize>(move (@37)) + storage_dead(@37) + @35 := chunks_exact<'_, i32>[{built_in impl Sized for i32}](move (@36), const (2 : usize)) + storage_dead(@36) + @34 := {impl IntoIterator for I}::into_iter[{built_in impl Sized for i32}]>[{built_in impl Sized for ChunksExact<'_, i32>[{built_in impl Sized for i32}]}, {impl Iterator for ChunksExact<'a, T>[@TraitClause0]}<'_, i32>[{built_in impl Sized for i32}]](move (@35)) + storage_dead(@35) + storage_live(iter@38) + iter@38 := move (@34) + loop { + storage_live(@39) + storage_live(@40) + storage_live(@41) + @41 := &mut iter@38 + @40 := &two-phase-mut *(@41) + @39 := {impl Iterator for ChunksExact<'a, T>[@TraitClause0]}::next<'_, '_, i32>[{built_in impl Sized for i32}](move (@40)) + storage_dead(@40) + match @39 { + Option::None => { + storage_dead(@41) + storage_dead(@39) + storage_dead(iter@38) + storage_dead(@34) + storage_live(expected@43) + expected@43 := const (28 : i32) + storage_live(@44) + storage_live(@45) + @45 := &i@2 + storage_live(@46) + @46 := &expected@43 + @44 := (move (@45), move (@46)) + storage_dead(@46) + storage_dead(@45) + storage_live(left_val@47) + left_val@47 := copy ((@44).0) + storage_live(right_val@48) + right_val@48 := copy ((@44).1) + storage_live(@49) + storage_live(@50) + @50 := copy (*(left_val@47)) + storage_live(@51) + @51 := copy (*(right_val@48)) + @49 := move (@50) == move (@51) + if move (@49) { + storage_dead(@51) + storage_dead(@50) + storage_dead(@49) + storage_dead(right_val@48) + storage_dead(left_val@47) + storage_dead(@44) + @0 := () + storage_dead(expected@43) + storage_dead(i@2) + storage_dead(a@1) + return + } + else { + storage_dead(@51) + storage_dead(@50) + storage_live(kind@52) + kind@52 := AssertKind::Eq { } + storage_live(@53) + @53 := move (kind@52) + storage_live(@54) + storage_live(@55) + @55 := &*(left_val@47) + @54 := &*(@55) + storage_live(@56) + storage_live(@57) + @57 := &*(right_val@48) + @56 := &*(@57) + storage_live(@58) + @58 := Option::None { } + panic(core::panicking::assert_failed) + } + }, + Option::Some => { + @42 := copy (i@2) panic.+ const (1 : i32) + i@2 := move (@42) + storage_dead(@41) + storage_dead(@39) + }, + } + } + }, + Option::Some => { + @33 := copy (i@2) panic.+ const (1 : i32) + i@2 := move (@33) + storage_dead(@32) + storage_dead(@30) + }, + } + } + }, + Option::Some => { + storage_live(v@21) + v@21 := copy ((@18 as variant Option::Some).0) + storage_live(@22) + storage_live(@23) + @23 := &two-phase-mut i@2 + storage_live(@24) + @24 := copy (v@21) + @22 := {impl AddAssign<&'_0 (i32)> for i32}::add_assign<'_, '_>(move (@23), move (@24)) + storage_dead(@24) + storage_dead(@23) + storage_dead(@22) + storage_dead(v@21) + storage_dead(@20) + storage_dead(@18) + }, + } + } }, Option::Some => { storage_live(v@10) @@ -5268,192 +5443,9 @@ fn main() storage_dead(v@10) storage_dead(@9) storage_dead(@7) - continue 0 - }, - } - } - storage_dead(@9) - storage_dead(@7) - drop[{impl Destruct for IntoIter[@TraitClause0]}[{built_in impl Sized for i32}]] iter@6 - storage_dead(iter@6) - drop[{impl Destruct for IntoIter[@TraitClause0]}[{built_in impl Sized for i32}]] @3 - storage_dead(@3) - storage_live(@13) - storage_live(@14) - storage_live(@15) - storage_live(@16) - @16 := &a@1 - @15 := @ArrayToSliceShared<'_, i32, 7 : usize>(move (@16)) - storage_dead(@16) - @14 := iter<'_, i32>[{built_in impl Sized for i32}](move (@15)) - storage_dead(@15) - @13 := {impl IntoIterator for I}::into_iter[{built_in impl Sized for i32}]>[{built_in impl Sized for Iter<'_, i32>[{built_in impl Sized for i32}]}, {impl Iterator for Iter<'a, T>[@TraitClause0]}<'_, i32>[{built_in impl Sized for i32}]](move (@14)) - storage_dead(@14) - storage_live(iter@17) - iter@17 := move (@13) - loop { - storage_live(@18) - storage_live(@19) - storage_live(@20) - @20 := &mut iter@17 - @19 := &two-phase-mut *(@20) - @18 := {impl Iterator for Iter<'a, T>[@TraitClause0]}::next<'_, '_, i32>[{built_in impl Sized for i32}](move (@19)) - storage_dead(@19) - match @18 { - Option::None => { - break 0 - }, - Option::Some => { - storage_live(v@21) - v@21 := copy ((@18 as variant Option::Some).0) - storage_live(@22) - storage_live(@23) - @23 := &two-phase-mut i@2 - storage_live(@24) - @24 := copy (v@21) - @22 := {impl AddAssign<&'_0 (i32)> for i32}::add_assign<'_, '_>(move (@23), move (@24)) - storage_dead(@24) - storage_dead(@23) - storage_dead(@22) - storage_dead(v@21) - storage_dead(@20) - storage_dead(@18) - continue 0 }, } } - storage_dead(@20) - storage_dead(@18) - storage_dead(iter@17) - storage_dead(@13) - storage_live(@25) - storage_live(@26) - storage_live(@27) - storage_live(@28) - @28 := &a@1 - @27 := @ArrayToSliceShared<'_, i32, 7 : usize>(move (@28)) - storage_dead(@28) - @26 := chunks<'_, i32>[{built_in impl Sized for i32}](move (@27), const (2 : usize)) - storage_dead(@27) - @25 := {impl IntoIterator for I}::into_iter[{built_in impl Sized for i32}]>[{built_in impl Sized for Chunks<'_, i32>[{built_in impl Sized for i32}]}, {impl Iterator for Chunks<'a, T>[@TraitClause0]}<'_, i32>[{built_in impl Sized for i32}]](move (@26)) - storage_dead(@26) - storage_live(iter@29) - iter@29 := move (@25) - loop { - storage_live(@30) - storage_live(@31) - storage_live(@32) - @32 := &mut iter@29 - @31 := &two-phase-mut *(@32) - @30 := {impl Iterator for Chunks<'a, T>[@TraitClause0]}::next<'_, '_, i32>[{built_in impl Sized for i32}](move (@31)) - storage_dead(@31) - match @30 { - Option::None => { - break 0 - }, - Option::Some => { - @33 := copy (i@2) panic.+ const (1 : i32) - i@2 := move (@33) - storage_dead(@32) - storage_dead(@30) - continue 0 - }, - } - } - storage_dead(@32) - storage_dead(@30) - storage_dead(iter@29) - storage_dead(@25) - storage_live(@34) - storage_live(@35) - storage_live(@36) - storage_live(@37) - @37 := &a@1 - @36 := @ArrayToSliceShared<'_, i32, 7 : usize>(move (@37)) - storage_dead(@37) - @35 := chunks_exact<'_, i32>[{built_in impl Sized for i32}](move (@36), const (2 : usize)) - storage_dead(@36) - @34 := {impl IntoIterator for I}::into_iter[{built_in impl Sized for i32}]>[{built_in impl Sized for ChunksExact<'_, i32>[{built_in impl Sized for i32}]}, {impl Iterator for ChunksExact<'a, T>[@TraitClause0]}<'_, i32>[{built_in impl Sized for i32}]](move (@35)) - storage_dead(@35) - storage_live(iter@38) - iter@38 := move (@34) - loop { - storage_live(@39) - storage_live(@40) - storage_live(@41) - @41 := &mut iter@38 - @40 := &two-phase-mut *(@41) - @39 := {impl Iterator for ChunksExact<'a, T>[@TraitClause0]}::next<'_, '_, i32>[{built_in impl Sized for i32}](move (@40)) - storage_dead(@40) - match @39 { - Option::None => { - break 0 - }, - Option::Some => { - @42 := copy (i@2) panic.+ const (1 : i32) - i@2 := move (@42) - storage_dead(@41) - storage_dead(@39) - continue 0 - }, - } - } - storage_dead(@41) - storage_dead(@39) - storage_dead(iter@38) - storage_dead(@34) - storage_live(expected@43) - expected@43 := const (28 : i32) - storage_live(@44) - storage_live(@45) - @45 := &i@2 - storage_live(@46) - @46 := &expected@43 - @44 := (move (@45), move (@46)) - storage_dead(@46) - storage_dead(@45) - storage_live(left_val@47) - left_val@47 := copy ((@44).0) - storage_live(right_val@48) - right_val@48 := copy ((@44).1) - storage_live(@49) - storage_live(@50) - @50 := copy (*(left_val@47)) - storage_live(@51) - @51 := copy (*(right_val@48)) - @49 := move (@50) == move (@51) - if move (@49) { - } - else { - storage_dead(@51) - storage_dead(@50) - storage_live(kind@52) - kind@52 := AssertKind::Eq { } - storage_live(@53) - @53 := move (kind@52) - storage_live(@54) - storage_live(@55) - @55 := &*(left_val@47) - @54 := &*(@55) - storage_live(@56) - storage_live(@57) - @57 := &*(right_val@48) - @56 := &*(@57) - storage_live(@58) - @58 := Option::None { } - panic(core::panicking::assert_failed) - } - storage_dead(@51) - storage_dead(@50) - storage_dead(@49) - storage_dead(right_val@48) - storage_dead(left_val@47) - storage_dead(@44) - @0 := () - storage_dead(expected@43) - storage_dead(i@2) - storage_dead(a@1) - return } diff --git a/charon/tests/ui/loops.out b/charon/tests/ui/loops.out index 48486d6e8..2b590a74a 100644 --- a/charon/tests/ui/loops.out +++ b/charon/tests/ui/loops.out @@ -905,21 +905,19 @@ pub fn test_loop1(@1: u32) -> u32 @9 := copy (i@2) panic.+ const (1 : u32) i@2 := move (@9) storage_dead(@4) - continue 0 } else { - break 0 + storage_dead(@6) + storage_dead(@5) + storage_dead(@4) + @10 := copy (s@3) panic.* const (2 : u32) + s@3 := move (@10) + @0 := copy (s@3) + storage_dead(s@3) + storage_dead(i@2) + return } } - storage_dead(@6) - storage_dead(@5) - storage_dead(@4) - @10 := copy (s@3) panic.* const (2 : u32) - s@3 := move (@10) - @0 := copy (s@3) - storage_dead(s@3) - storage_dead(i@2) - return } // Full name: test_crate::test_loop2 @@ -938,12 +936,15 @@ pub fn test_loop2(@1: u32) -> u32 let @10: u32; // anonymous local let @11: u32; // anonymous local - storage_live(@10) - storage_live(@11) - storage_live(i@2) - i@2 := const (0 : u32) - storage_live(s@3) - s@3 := const (0 : u32) + loop { + storage_live(@10) + storage_live(@11) + storage_live(i@2) + i@2 := const (0 : u32) + storage_live(s@3) + s@3 := const (0 : u32) + break 0 + } loop { storage_live(@4) storage_live(@5) @@ -959,6 +960,8 @@ pub fn test_loop2(@1: u32) -> u32 @8 := copy (i@2) @7 := move (@8) == const (17 : u32) if move (@7) { + storage_dead(@8) + storage_dead(@7) } else { storage_dead(@8) @@ -973,21 +976,17 @@ pub fn test_loop2(@1: u32) -> u32 storage_dead(@4) continue 0 } - storage_dead(@8) - storage_dead(@7) - break 0 } else { storage_dead(@6) storage_dead(@5) - break 0 } + storage_dead(@4) + @0 := copy (s@3) + storage_dead(s@3) + storage_dead(i@2) + return } - storage_dead(@4) - @0 := copy (s@3) - storage_dead(s@3) - storage_dead(i@2) - return } // Full name: test_crate::test_loop3 @@ -1016,17 +1015,20 @@ pub fn test_loop3(@1: u32) -> u32 let @20: u32; // anonymous local let @21: u32; // anonymous local - storage_live(@15) - storage_live(@17) - storage_live(@18) - storage_live(@20) - storage_live(@21) - storage_live(i@2) - i@2 := const (0 : u32) - storage_live(j@3) - j@3 := const (0 : u32) - storage_live(s@4) - s@4 := const (0 : u32) + loop { + storage_live(@15) + storage_live(@17) + storage_live(@18) + storage_live(@20) + storage_live(@21) + storage_live(i@2) + i@2 := const (0 : u32) + storage_live(j@3) + j@3 := const (0 : u32) + storage_live(s@4) + s@4 := const (0 : u32) + break 0 + } loop { storage_live(@5) storage_live(@6) @@ -1059,6 +1061,9 @@ pub fn test_loop3(@1: u32) -> u32 storage_dead(@13) @11 := move (@12) == const (17 : u32) if move (@11) { + storage_dead(@12) + storage_dead(@11) + storage_dead(@8) } else { storage_dead(@12) @@ -1074,41 +1079,35 @@ pub fn test_loop3(@1: u32) -> u32 storage_dead(@5) continue 1 } - storage_dead(@12) - storage_dead(@11) - storage_dead(@8) - continue 0 } else { - break 0 + storage_dead(@10) + storage_dead(@9) + storage_dead(@8) + j@3 := const (0 : u32) + storage_live(@19) + @19 := copy (i@2) + @20 := copy (s@4) panic.+ copy (@19) + s@4 := move (@20) + storage_dead(@19) + @21 := copy (i@2) panic.+ const (1 : u32) + i@2 := move (@21) + storage_dead(@5) + continue 1 } } - storage_dead(@10) - storage_dead(@9) - storage_dead(@8) - j@3 := const (0 : u32) - storage_live(@19) - @19 := copy (i@2) - @20 := copy (s@4) panic.+ copy (@19) - s@4 := move (@20) - storage_dead(@19) - @21 := copy (i@2) panic.+ const (1 : u32) - i@2 := move (@21) - storage_dead(@5) - continue 0 } else { - break 0 + storage_dead(@7) + storage_dead(@6) + storage_dead(@5) + @0 := copy (s@4) + storage_dead(s@4) + storage_dead(j@3) + storage_dead(i@2) + return } } - storage_dead(@7) - storage_dead(@6) - storage_dead(@5) - @0 := copy (s@4) - storage_dead(s@4) - storage_dead(j@3) - storage_dead(i@2) - return } // Full name: test_crate::test_loop4 @@ -1137,98 +1136,101 @@ pub fn test_loop4(@1: u32) -> u32 let @20: u32; // anonymous local let @21: u32; // anonymous local - storage_live(@15) - storage_live(@17) - storage_live(@18) - storage_live(@20) - storage_live(@21) - storage_live(i@2) - i@2 := const (1 : u32) - storage_live(j@3) - j@3 := const (0 : u32) - storage_live(s@4) - s@4 := const (0 : u32) loop { - storage_live(@5) - storage_live(@6) - @6 := copy (i@2) - storage_live(@7) - @7 := copy (max@1) - @5 := move (@6) < move (@7) - if move (@5) { - storage_dead(@7) - storage_dead(@6) - loop { - storage_live(@8) - storage_live(@9) - @9 := copy (j@3) - storage_live(@10) - @10 := copy (max@1) - @8 := move (@9) < move (@10) - if move (@8) { - storage_dead(@10) - storage_dead(@9) - storage_live(@11) - storage_live(@12) - storage_live(@13) - @13 := copy (i@2) - storage_live(@14) - @14 := copy (j@3) - @15 := copy (@13) panic.+ copy (@14) - @12 := move (@15) - storage_dead(@14) - storage_dead(@13) - @11 := move (@12) == const (17 : u32) - if move (@11) { - storage_dead(@12) - storage_dead(@11) - storage_dead(@8) - continue 0 + storage_live(@15) + storage_live(@17) + storage_live(@18) + storage_live(@20) + storage_live(@21) + storage_live(i@2) + i@2 := const (1 : u32) + storage_live(j@3) + j@3 := const (0 : u32) + storage_live(s@4) + s@4 := const (0 : u32) + break 0 + } + loop { + loop { + storage_live(@5) + storage_live(@6) + @6 := copy (i@2) + storage_live(@7) + @7 := copy (max@1) + @5 := move (@6) < move (@7) + if move (@5) { + storage_dead(@7) + storage_dead(@6) + loop { + storage_live(@8) + storage_live(@9) + @9 := copy (j@3) + storage_live(@10) + @10 := copy (max@1) + @8 := move (@9) < move (@10) + if move (@8) { + storage_dead(@10) + storage_dead(@9) + storage_live(@11) + storage_live(@12) + storage_live(@13) + @13 := copy (i@2) + storage_live(@14) + @14 := copy (j@3) + @15 := copy (@13) panic.+ copy (@14) + @12 := move (@15) + storage_dead(@14) + storage_dead(@13) + @11 := move (@12) == const (17 : u32) + if move (@11) { + storage_dead(@12) + storage_dead(@11) + storage_dead(@8) + } + else { + storage_dead(@12) + storage_dead(@11) + storage_live(@16) + @16 := copy (i@2) + @17 := copy (s@4) panic.+ copy (@16) + s@4 := move (@17) + storage_dead(@16) + @18 := copy (j@3) panic.+ const (1 : u32) + j@3 := move (@18) + storage_dead(@8) + break 1 + } } else { - storage_dead(@12) - storage_dead(@11) - storage_live(@16) - @16 := copy (i@2) - @17 := copy (s@4) panic.+ copy (@16) - s@4 := move (@17) - storage_dead(@16) - @18 := copy (j@3) panic.+ const (1 : u32) - j@3 := move (@18) + storage_dead(@10) + storage_dead(@9) storage_dead(@8) - break 1 + j@3 := const (0 : u32) + storage_live(@19) + @19 := copy (i@2) + @20 := copy (s@4) panic.+ copy (@19) + s@4 := move (@20) + storage_dead(@19) + @21 := copy (i@2) panic.+ const (1 : u32) + i@2 := move (@21) + storage_dead(@5) + continue 2 } } - else { - break 0 - } } - storage_dead(@10) - storage_dead(@9) - storage_dead(@8) - j@3 := const (0 : u32) - storage_live(@19) - @19 := copy (i@2) - @20 := copy (s@4) panic.+ copy (@19) - s@4 := move (@20) - storage_dead(@19) - @21 := copy (i@2) panic.+ const (1 : u32) - i@2 := move (@21) - storage_dead(@5) - continue 0 - } - else { - storage_dead(@7) - storage_dead(@6) + else { + storage_dead(@7) + storage_dead(@6) + } break 0 } + storage_dead(@5) + @0 := copy (s@4) + storage_dead(s@4) + storage_dead(j@3) + storage_dead(i@2) + return } - storage_dead(@5) - @0 := copy (s@4) - storage_dead(s@4) - storage_dead(j@3) - storage_dead(i@2) - return } // Full name: test_crate::test_loop5 @@ -1252,16 +1254,19 @@ pub fn test_loop5(@1: u32) -> u32 let @15: u32; // anonymous local let @16: u32; // anonymous local - storage_live(@12) - storage_live(@13) - storage_live(@15) - storage_live(@16) - storage_live(i@2) - i@2 := const (0 : u32) - storage_live(j@3) - j@3 := const (0 : u32) - storage_live(s@4) - s@4 := const (0 : u32) + loop { + storage_live(@12) + storage_live(@13) + storage_live(@15) + storage_live(@16) + storage_live(i@2) + i@2 := const (0 : u32) + storage_live(j@3) + j@3 := const (0 : u32) + storage_live(s@4) + s@4 := const (0 : u32) + break 0 + } loop { storage_live(@5) storage_live(@6) @@ -1290,37 +1295,34 @@ pub fn test_loop5(@1: u32) -> u32 @13 := copy (j@3) panic.+ const (1 : u32) j@3 := move (@13) storage_dead(@8) - continue 0 } else { - break 0 + storage_dead(@10) + storage_dead(@9) + storage_dead(@8) + storage_live(@14) + @14 := copy (i@2) + @15 := copy (s@4) panic.+ copy (@14) + s@4 := move (@15) + storage_dead(@14) + @16 := copy (i@2) panic.+ const (1 : u32) + i@2 := move (@16) + storage_dead(@5) + continue 1 } } - storage_dead(@10) - storage_dead(@9) - storage_dead(@8) - storage_live(@14) - @14 := copy (i@2) - @15 := copy (s@4) panic.+ copy (@14) - s@4 := move (@15) - storage_dead(@14) - @16 := copy (i@2) panic.+ const (1 : u32) - i@2 := move (@16) - storage_dead(@5) - continue 0 } else { - break 0 + storage_dead(@7) + storage_dead(@6) + storage_dead(@5) + @0 := copy (s@4) + storage_dead(s@4) + storage_dead(j@3) + storage_dead(i@2) + return } } - storage_dead(@7) - storage_dead(@6) - storage_dead(@5) - @0 := copy (s@4) - storage_dead(s@4) - storage_dead(j@3) - storage_dead(i@2) - return } // Full name: test_crate::test_loop6 @@ -1340,13 +1342,16 @@ pub fn test_loop6(@1: u32) -> u32 let @11: u32; // anonymous local let @12: u32; // anonymous local - storage_live(@10) - storage_live(@11) - storage_live(@12) - storage_live(i@2) - i@2 := const (0 : u32) - storage_live(s@3) - s@3 := const (0 : u32) + loop { + storage_live(@10) + storage_live(@11) + storage_live(@12) + storage_live(i@2) + i@2 := const (0 : u32) + storage_live(s@3) + s@3 := const (0 : u32) + break 0 + } loop { storage_live(@4) storage_live(@5) @@ -1362,6 +1367,8 @@ pub fn test_loop6(@1: u32) -> u32 @8 := copy (i@2) @7 := move (@8) > const (3 : u32) if move (@7) { + storage_dead(@8) + storage_dead(@7) } else { storage_dead(@8) @@ -1376,24 +1383,20 @@ pub fn test_loop6(@1: u32) -> u32 storage_dead(@4) continue 0 } - storage_dead(@8) - storage_dead(@7) - break 0 } else { storage_dead(@6) storage_dead(@5) - break 0 } + storage_dead(@4) + // All the below nodes are exit candidates (each of them is referenced twice) + @12 := copy (s@3) panic.+ const (1 : u32) + s@3 := move (@12) + @0 := copy (s@3) + storage_dead(s@3) + storage_dead(i@2) + return } - storage_dead(@4) - // All the below nodes are exit candidates (each of them is referenced twice) - @12 := copy (s@3) panic.+ const (1 : u32) - s@3 := move (@12) - @0 := copy (s@3) - storage_dead(s@3) - storage_dead(i@2) - return } // Full name: test_crate::test_loop7 @@ -1416,67 +1419,72 @@ pub fn test_loop7(@1: u32) -> u32 let @14: u32; // anonymous local let @15: u32; // anonymous local - storage_live(@13) - storage_live(@14) - storage_live(@15) - storage_live(i@2) - i@2 := const (0 : u32) - storage_live(s@3) - s@3 := const (0 : u32) - storage_live(@4) - storage_live(@5) - @5 := copy (i@2) - storage_live(@6) - @6 := copy (max@1) - @4 := move (@5) < move (@6) - if move (@4) { - storage_dead(@6) - storage_dead(@5) - loop { - storage_live(@7) - storage_live(@8) - @8 := copy (i@2) - storage_live(@9) - @9 := copy (max@1) - @7 := move (@8) < move (@9) - if move (@7) { - storage_dead(@9) - storage_dead(@8) - storage_live(@10) - storage_live(@11) - @11 := copy (i@2) - @10 := move (@11) > const (3 : u32) - if move (@10) { + loop { + storage_live(@13) + storage_live(@14) + storage_live(@15) + storage_live(i@2) + i@2 := const (0 : u32) + storage_live(s@3) + s@3 := const (0 : u32) + storage_live(@4) + storage_live(@5) + @5 := copy (i@2) + storage_live(@6) + @6 := copy (max@1) + @4 := move (@5) < move (@6) + if move (@4) { + loop { + storage_dead(@6) + storage_dead(@5) + break 0 + } + loop { + storage_live(@7) + storage_live(@8) + @8 := copy (i@2) + storage_live(@9) + @9 := copy (max@1) + @7 := move (@8) < move (@9) + if move (@7) { + storage_dead(@9) + storage_dead(@8) + storage_live(@10) + storage_live(@11) + @11 := copy (i@2) + @10 := move (@11) > const (3 : u32) + if move (@10) { + storage_dead(@11) + storage_dead(@10) + } + else { + storage_dead(@11) + storage_dead(@10) + storage_live(@12) + @12 := copy (i@2) + @13 := copy (s@3) panic.+ copy (@12) + s@3 := move (@13) + storage_dead(@12) + @14 := copy (i@2) panic.+ const (1 : u32) + i@2 := move (@14) + storage_dead(@7) + continue 0 + } } else { - storage_dead(@11) - storage_dead(@10) - storage_live(@12) - @12 := copy (i@2) - @13 := copy (s@3) panic.+ copy (@12) - s@3 := move (@13) - storage_dead(@12) - @14 := copy (i@2) panic.+ const (1 : u32) - i@2 := move (@14) - storage_dead(@7) - continue 0 + storage_dead(@9) + storage_dead(@8) } - storage_dead(@11) - storage_dead(@10) - break 0 - } - else { - storage_dead(@9) - storage_dead(@8) - break 0 + storage_dead(@7) + break 1 } } - storage_dead(@7) - } - else { - storage_dead(@6) - storage_dead(@5) - s@3 := const (2 : u32) + else { + storage_dead(@6) + storage_dead(@5) + s@3 := const (2 : u32) + } + break 0 } storage_dead(@4) @15 := copy (s@3) panic.+ const (1 : u32) @@ -1518,91 +1526,91 @@ pub fn test_loops() @3 := copy (x@1) @2 := move (@3) == const (2 : u32) if move (@2) { - } - else { storage_dead(@3) - panic(core::panicking::panic) - } - storage_dead(@3) - storage_dead(@2) - storage_live(x@4) - x@4 := test_loop2(const (2 : u32)) - storage_live(@5) - storage_live(@6) - @6 := copy (x@4) - @5 := move (@6) == const (1 : u32) - if move (@5) { - } - else { - storage_dead(@6) - panic(core::panicking::panic) - } - storage_dead(@6) - storage_dead(@5) - storage_live(x@7) - x@7 := test_loop3(const (2 : u32)) - storage_live(@8) - storage_live(@9) - @9 := copy (x@7) - @8 := move (@9) == const (3 : u32) - if move (@8) { - } - else { - storage_dead(@9) - panic(core::panicking::panic) - } - storage_dead(@9) - storage_dead(@8) - storage_live(x@10) - x@10 := test_loop4(const (20 : u32)) - storage_live(@11) - storage_live(@12) - @12 := copy (x@10) - @11 := move (@12) == const (1 : u32) - if move (@11) { - } - else { - storage_dead(@12) - panic(core::panicking::panic) - } - storage_dead(@12) - storage_dead(@11) - storage_live(x@13) - x@13 := test_loop5(const (2 : u32)) - storage_live(@14) - storage_live(@15) - @15 := copy (x@13) - @14 := move (@15) == const (2 : u32) - if move (@14) { - } - else { - storage_dead(@15) - panic(core::panicking::panic) - } - storage_dead(@15) - storage_dead(@14) - storage_live(x@16) - x@16 := test_loop6(const (2 : u32)) - storage_live(@17) - storage_live(@18) - @18 := copy (x@16) - @17 := move (@18) == const (2 : u32) - if move (@17) { + storage_dead(@2) + storage_live(x@4) + x@4 := test_loop2(const (2 : u32)) + storage_live(@5) + storage_live(@6) + @6 := copy (x@4) + @5 := move (@6) == const (1 : u32) + if move (@5) { + storage_dead(@6) + storage_dead(@5) + storage_live(x@7) + x@7 := test_loop3(const (2 : u32)) + storage_live(@8) + storage_live(@9) + @9 := copy (x@7) + @8 := move (@9) == const (3 : u32) + if move (@8) { + storage_dead(@9) + storage_dead(@8) + storage_live(x@10) + x@10 := test_loop4(const (20 : u32)) + storage_live(@11) + storage_live(@12) + @12 := copy (x@10) + @11 := move (@12) == const (1 : u32) + if move (@11) { + storage_dead(@12) + storage_dead(@11) + storage_live(x@13) + x@13 := test_loop5(const (2 : u32)) + storage_live(@14) + storage_live(@15) + @15 := copy (x@13) + @14 := move (@15) == const (2 : u32) + if move (@14) { + storage_dead(@15) + storage_dead(@14) + storage_live(x@16) + x@16 := test_loop6(const (2 : u32)) + storage_live(@17) + storage_live(@18) + @18 := copy (x@16) + @17 := move (@18) == const (2 : u32) + if move (@17) { + storage_dead(@18) + storage_dead(@17) + @0 := () + storage_dead(x@16) + storage_dead(x@13) + storage_dead(x@10) + storage_dead(x@7) + storage_dead(x@4) + storage_dead(x@1) + return + } + else { + storage_dead(@18) + panic(core::panicking::panic) + } + } + else { + storage_dead(@15) + panic(core::panicking::panic) + } + } + else { + storage_dead(@12) + panic(core::panicking::panic) + } + } + else { + storage_dead(@9) + panic(core::panicking::panic) + } + } + else { + storage_dead(@6) + panic(core::panicking::panic) + } } else { - storage_dead(@18) + storage_dead(@3) panic(core::panicking::panic) } - storage_dead(@18) - storage_dead(@17) - @0 := () - storage_dead(x@16) - storage_dead(x@13) - storage_dead(x@10) - storage_dead(x@7) - storage_dead(x@4) - storage_dead(x@1) - return } // Full name: test_crate::nested_loops_enum @@ -1656,92 +1664,90 @@ pub fn nested_loops_enum(@1: usize, @2: usize) -> usize storage_dead(@8) match @7 { Option::None => { - break 0 - }, - Option::Some => { - @10 := copy (s@3) panic.+ const (1 : usize) - s@3 := move (@10) storage_dead(@9) storage_dead(@7) - continue 0 - }, - } - } - storage_dead(@9) - storage_dead(@7) - storage_dead(iter@6) - storage_dead(@4) - storage_live(@11) - storage_live(@12) - storage_live(@13) - @13 := copy (step_out@1) - @12 := Range { start: const (0 : usize), end: move (@13) } - storage_dead(@13) - @11 := {impl IntoIterator for I}::into_iter[{built_in impl Sized for usize}]>[{built_in impl Sized for Range[{built_in impl Sized for usize}]}, {impl Iterator for Range[@TraitClause0]}[{built_in impl Sized for usize}, {impl Step for usize}]](move (@12)) - storage_dead(@12) - storage_live(iter@14) - iter@14 := move (@11) - loop { - storage_live(@15) - storage_live(@16) - storage_live(@17) - @17 := &mut iter@14 - @16 := &two-phase-mut *(@17) - @15 := {impl Iterator for Range[@TraitClause0]}::next<'_, usize>[{built_in impl Sized for usize}, {impl Step for usize}](move (@16)) - storage_dead(@16) - match @15 { - Option::None => { - break 0 - }, - Option::Some => { - storage_live(@18) - storage_live(@19) - storage_live(@20) - @20 := copy (step_in@2) - @19 := Range { start: const (0 : usize), end: move (@20) } - storage_dead(@20) - @18 := {impl IntoIterator for I}::into_iter[{built_in impl Sized for usize}]>[{built_in impl Sized for Range[{built_in impl Sized for usize}]}, {impl Iterator for Range[@TraitClause0]}[{built_in impl Sized for usize}, {impl Step for usize}]](move (@19)) - storage_dead(@19) - storage_live(iter@21) - iter@21 := move (@18) + storage_dead(iter@6) + storage_dead(@4) + storage_live(@11) + storage_live(@12) + storage_live(@13) + @13 := copy (step_out@1) + @12 := Range { start: const (0 : usize), end: move (@13) } + storage_dead(@13) + @11 := {impl IntoIterator for I}::into_iter[{built_in impl Sized for usize}]>[{built_in impl Sized for Range[{built_in impl Sized for usize}]}, {impl Iterator for Range[@TraitClause0]}[{built_in impl Sized for usize}, {impl Step for usize}]](move (@12)) + loop { + storage_dead(@12) + storage_live(iter@14) + iter@14 := move (@11) + break 0 + } loop { - storage_live(@22) - storage_live(@23) - storage_live(@24) - @24 := &mut iter@21 - @23 := &two-phase-mut *(@24) - @22 := {impl Iterator for Range[@TraitClause0]}::next<'_, usize>[{built_in impl Sized for usize}, {impl Step for usize}](move (@23)) - storage_dead(@23) - match @22 { + storage_live(@15) + storage_live(@16) + storage_live(@17) + @17 := &mut iter@14 + @16 := &two-phase-mut *(@17) + @15 := {impl Iterator for Range[@TraitClause0]}::next<'_, usize>[{built_in impl Sized for usize}, {impl Step for usize}](move (@16)) + storage_dead(@16) + match @15 { Option::None => { - break 0 + storage_dead(@17) + storage_dead(@15) + storage_dead(iter@14) + storage_dead(@11) + @0 := copy (s@3) + storage_dead(s@3) + return }, Option::Some => { - @25 := copy (s@3) panic.+ const (1 : usize) - s@3 := move (@25) - storage_dead(@24) - storage_dead(@22) - continue 0 + storage_live(@18) + storage_live(@19) + storage_live(@20) + @20 := copy (step_in@2) + @19 := Range { start: const (0 : usize), end: move (@20) } + storage_dead(@20) + @18 := {impl IntoIterator for I}::into_iter[{built_in impl Sized for usize}]>[{built_in impl Sized for Range[{built_in impl Sized for usize}]}, {impl Iterator for Range[@TraitClause0]}[{built_in impl Sized for usize}, {impl Step for usize}]](move (@19)) + storage_dead(@19) + storage_live(iter@21) + iter@21 := move (@18) + loop { + storage_live(@22) + storage_live(@23) + storage_live(@24) + @24 := &mut iter@21 + @23 := &two-phase-mut *(@24) + @22 := {impl Iterator for Range[@TraitClause0]}::next<'_, usize>[{built_in impl Sized for usize}, {impl Step for usize}](move (@23)) + storage_dead(@23) + match @22 { + Option::None => { + storage_dead(@24) + storage_dead(@22) + storage_dead(iter@21) + storage_dead(@18) + storage_dead(@17) + storage_dead(@15) + continue 1 + }, + Option::Some => { + @25 := copy (s@3) panic.+ const (1 : usize) + s@3 := move (@25) + storage_dead(@24) + storage_dead(@22) + }, + } + } }, } } - storage_dead(@24) - storage_dead(@22) - storage_dead(iter@21) - storage_dead(@18) - storage_dead(@17) - storage_dead(@15) - continue 0 + }, + Option::Some => { + @10 := copy (s@3) panic.+ const (1 : usize) + s@3 := move (@10) + storage_dead(@9) + storage_dead(@7) }, } } - storage_dead(@17) - storage_dead(@15) - storage_dead(iter@14) - storage_dead(@11) - @0 := copy (s@3) - storage_dead(s@3) - return } // Full name: test_crate::loop_inside_if @@ -1763,58 +1769,60 @@ pub fn loop_inside_if(@1: bool, @2: u32) -> u32 let @13: u32; // anonymous local let @14: u32; // anonymous local - storage_live(@14) - storage_live(@3) - @3 := copy (b@1) - if move (@3) { - storage_live(s@4) - s@4 := const (0 : u32) - storage_live(@5) - storage_live(@6) - storage_live(@7) - @7 := copy (n@2) - @6 := Range { start: const (0 : u32), end: move (@7) } - storage_dead(@7) - @5 := {impl IntoIterator for I}::into_iter[{built_in impl Sized for u32}]>[{built_in impl Sized for Range[{built_in impl Sized for u32}]}, {impl Iterator for Range[@TraitClause0]}[{built_in impl Sized for u32}, {impl Step for u32}]](move (@6)) - storage_dead(@6) - storage_live(iter@8) - iter@8 := move (@5) - loop { - storage_live(@9) - storage_live(@10) - storage_live(@11) - @11 := &mut iter@8 - @10 := &two-phase-mut *(@11) - @9 := {impl Iterator for Range[@TraitClause0]}::next<'_, u32>[{built_in impl Sized for u32}, {impl Step for u32}](move (@10)) - storage_dead(@10) - match @9 { - Option::None => { - break 0 - }, - Option::Some => { - storage_live(i@12) - i@12 := copy ((@9 as variant Option::Some).0) - storage_live(@13) - @13 := copy (i@12) - @14 := copy (s@4) panic.+ copy (@13) - s@4 := move (@14) - storage_dead(@13) - storage_dead(i@12) - storage_dead(@11) - storage_dead(@9) - continue 0 - }, + loop { + storage_live(@14) + storage_live(@3) + @3 := copy (b@1) + if move (@3) { + storage_live(s@4) + s@4 := const (0 : u32) + storage_live(@5) + storage_live(@6) + storage_live(@7) + @7 := copy (n@2) + @6 := Range { start: const (0 : u32), end: move (@7) } + storage_dead(@7) + @5 := {impl IntoIterator for I}::into_iter[{built_in impl Sized for u32}]>[{built_in impl Sized for Range[{built_in impl Sized for u32}]}, {impl Iterator for Range[@TraitClause0]}[{built_in impl Sized for u32}, {impl Step for u32}]](move (@6)) + storage_dead(@6) + storage_live(iter@8) + iter@8 := move (@5) + loop { + storage_live(@9) + storage_live(@10) + storage_live(@11) + @11 := &mut iter@8 + @10 := &two-phase-mut *(@11) + @9 := {impl Iterator for Range[@TraitClause0]}::next<'_, u32>[{built_in impl Sized for u32}, {impl Step for u32}](move (@10)) + storage_dead(@10) + match @9 { + Option::None => { + storage_dead(@11) + storage_dead(@9) + storage_dead(iter@8) + storage_dead(@5) + @0 := copy (s@4) + storage_dead(s@4) + break 1 + }, + Option::Some => { + storage_live(i@12) + i@12 := copy ((@9 as variant Option::Some).0) + storage_live(@13) + @13 := copy (i@12) + @14 := copy (s@4) panic.+ copy (@13) + s@4 := move (@14) + storage_dead(@13) + storage_dead(i@12) + storage_dead(@11) + storage_dead(@9) + }, + } } } - storage_dead(@11) - storage_dead(@9) - storage_dead(iter@8) - storage_dead(@5) - @0 := copy (s@4) - storage_dead(s@4) - } - else { - @0 := const (0 : u32) + else { + @0 := const (0 : u32) + } + break 0 } storage_dead(@3) return @@ -1859,21 +1867,19 @@ pub fn test_crate::sum(@1: u32) -> u32 @9 := copy (i@2) panic.+ const (1 : u32) i@2 := move (@9) storage_dead(@4) - continue 0 } else { - break 0 + storage_dead(@6) + storage_dead(@5) + storage_dead(@4) + @10 := copy (s@3) panic.* const (2 : u32) + s@3 := move (@10) + @0 := copy (s@3) + storage_dead(s@3) + storage_dead(i@2) + return } } - storage_dead(@6) - storage_dead(@5) - storage_dead(@4) - @10 := copy (s@3) panic.* const (2 : u32) - s@3 := move (@10) - @0 := copy (s@3) - storage_dead(s@3) - storage_dead(i@2) - return } // Full name: test_crate::sum_array @@ -1920,18 +1926,16 @@ pub fn sum_array(@1: Array) -> u32 @9 := copy (i@2) panic.+ const (1 : usize) i@2 := move (@9) storage_dead(@4) - continue 0 } else { - break 0 + storage_dead(@5) + storage_dead(@4) + @0 := copy (s@3) + storage_dead(s@3) + storage_dead(i@2) + return } } - storage_dead(@5) - storage_dead(@4) - @0 := copy (s@3) - storage_dead(s@3) - storage_dead(i@2) - return } // Full name: test_crate::clear @@ -1964,33 +1968,31 @@ pub fn clear<'_0>(@1: &'_0 mut (Vec[{built_in impl Sized for u32}, {built_i storage_dead(@6) @3 := move (@4) < move (@5) if move (@3) { + storage_dead(@5) + storage_dead(@4) + storage_live(@7) + storage_live(@8) + @8 := &mut *(v@1) + storage_live(@9) + @9 := copy (i@2) + @7 := {impl IndexMut for Vec[@TraitClause0, @TraitClause2]}::index_mut<'_, u32, usize, Global>[{built_in impl Sized for u32}, {built_in impl Sized for usize}, {built_in impl Sized for Global}, {impl SliceIndex> for usize}[{built_in impl Sized for u32}]](move (@8), move (@9)) + storage_dead(@9) + storage_dead(@8) + *(@7) := const (0 : u32) + storage_dead(@7) + @10 := copy (i@2) panic.+ const (1 : usize) + i@2 := move (@10) + storage_dead(@3) } else { - break 0 + storage_dead(@5) + storage_dead(@4) + @0 := () + storage_dead(@3) + storage_dead(i@2) + return } - storage_dead(@5) - storage_dead(@4) - storage_live(@7) - storage_live(@8) - @8 := &mut *(v@1) - storage_live(@9) - @9 := copy (i@2) - @7 := {impl IndexMut for Vec[@TraitClause0, @TraitClause2]}::index_mut<'_, u32, usize, Global>[{built_in impl Sized for u32}, {built_in impl Sized for usize}, {built_in impl Sized for Global}, {impl SliceIndex> for usize}[{built_in impl Sized for u32}]](move (@8), move (@9)) - storage_dead(@9) - storage_dead(@8) - *(@7) := const (0 : u32) - storage_dead(@7) - @10 := copy (i@2) panic.+ const (1 : usize) - i@2 := move (@10) - storage_dead(@3) - continue 0 } - storage_dead(@5) - storage_dead(@4) - @0 := () - storage_dead(@3) - storage_dead(i@2) - return } // Full name: test_crate::List @@ -2029,6 +2031,13 @@ pub fn get_elem_mut<'_0>(@1: &'_0 mut (List[{built_in impl Sized for usiz @7 := copy (x@2) @5 := move (@6) == move (@7) if move (@5) { + storage_dead(@7) + storage_dead(@6) + @0 := &mut *(y@3) + storage_dead(@5) + storage_dead(tl@4) + storage_dead(y@3) + return } else { storage_dead(@7) @@ -2040,15 +2049,7 @@ pub fn get_elem_mut<'_0>(@1: &'_0 mut (List[{built_in impl Sized for usiz storage_dead(@5) storage_dead(tl@4) storage_dead(y@3) - continue 0 } - storage_dead(@7) - storage_dead(@6) - @0 := &mut *(y@3) - storage_dead(@5) - storage_dead(tl@4) - storage_dead(y@3) - return }, List::Nil => { panic(core::panicking::panic) @@ -2085,6 +2086,12 @@ where @6 := copy (i@2) @5 := move (@6) == const (0 : u32) if move (@5) { + storage_dead(@6) + @0 := &mut *(x@3) + storage_dead(@5) + storage_dead(tl@4) + storage_dead(x@3) + return } else { storage_dead(@6) @@ -2097,14 +2104,7 @@ where storage_dead(@5) storage_dead(tl@4) storage_dead(x@3) - continue 0 } - storage_dead(@6) - @0 := &mut *(x@3) - storage_dead(@5) - storage_dead(tl@4) - storage_dead(x@3) - return }, _ => { panic(core::panicking::panic) diff --git a/charon/tests/ui/matches.out b/charon/tests/ui/matches.out index 4b2640d05..c7f529330 100644 --- a/charon/tests/ui/matches.out +++ b/charon/tests/ui/matches.out @@ -49,14 +49,14 @@ pub fn test1(@1: E1) -> bool match x@1 { E1::V1 | E1::V2 => { + @0 := const (true) + return }, E1::V3 => { @0 := const (false) return }, } - @0 := const (true) - return } // Full name: test_crate::id @@ -117,24 +117,26 @@ pub fn test3(@1: E2) -> u32 let @6: u32; // anonymous local let @7: u32; // anonymous local - storage_live(@7) - storage_live(y@2) - match x@1 { - E2::V1 => { - storage_live(n@3) - n@3 := copy ((x@1 as variant E2::V1).0) - y@2 := copy (n@3) - storage_dead(n@3) - }, - E2::V2 => { - storage_live(n@3) - n@3 := copy ((x@1 as variant E2::V2).0) - y@2 := copy (n@3) - storage_dead(n@3) - }, - E2::V3 => { - y@2 := const (0 : u32) - }, + loop { + storage_live(@7) + storage_live(y@2) + match x@1 { + E2::V1 => { + storage_live(n@3) + n@3 := copy ((x@1 as variant E2::V1).0) + }, + E2::V2 => { + storage_live(n@3) + n@3 := copy ((x@1 as variant E2::V2).0) + }, + E2::V3 => { + y@2 := const (0 : u32) + break 0 + }, + } + y@2 := copy (n@3) + storage_dead(n@3) + break 0 } storage_live(z@4) z@4 := id[{built_in impl Sized for u32}](const (3 : u32)) diff --git a/charon/tests/ui/monomorphization/adt_proj.out b/charon/tests/ui/monomorphization/adt_proj.out index 05a7bc7bf..4a1cb205a 100644 --- a/charon/tests/ui/monomorphization/adt_proj.out +++ b/charon/tests/ui/monomorphization/adt_proj.out @@ -41,17 +41,17 @@ fn main() res@1 := Result::::Ok { 0: const (0 : u32) } match res@1 { Result::::Ok => { + storage_live(n@2) + n@2 := copy ((res@1 as variant Result::::Ok).0) + @0 := () + storage_dead(n@2) + storage_dead(res@1) + return }, _ => { panic(core::panicking::panic) }, } - storage_live(n@2) - n@2 := copy ((res@1 as variant Result::::Ok).0) - @0 := () - storage_dead(n@2) - storage_dead(res@1) - return } diff --git a/charon/tests/ui/no_nested_borrows.out b/charon/tests/ui/no_nested_borrows.out index f6423889c..3c8af66c8 100644 --- a/charon/tests/ui/no_nested_borrows.out +++ b/charon/tests/ui/no_nested_borrows.out @@ -490,19 +490,19 @@ pub fn test_box1() @7 := copy (*(x@4)) @6 := move (@7) == const (1 : i32) if move (@6) { + storage_dead(@7) + storage_dead(@6) + @0 := () + storage_dead(x@4) + storage_dead(x@2) + drop[{impl Destruct for alloc::boxed::Box[@TraitClause0, @TraitClause1]}[{built_in impl MetaSized for i32}, {built_in impl Sized for Global}]] b@1 + storage_dead(b@1) + return } else { storage_dead(@7) panic(core::panicking::panic) } - storage_dead(@7) - storage_dead(@6) - @0 := () - storage_dead(x@4) - storage_dead(x@2) - drop[{impl Destruct for alloc::boxed::Box[@TraitClause0, @TraitClause1]}[{built_in impl MetaSized for i32}, {built_in impl Sized for Global}]] b@1 - storage_dead(b@1) - return } // Full name: test_crate::copy_int @@ -541,14 +541,14 @@ where match *(l@1) { List::Cons => { + @0 := const (true) + return }, List::Nil => { @0 := const (false) return }, } - @0 := const (true) - return } // Full name: test_crate::split_list @@ -565,30 +565,30 @@ where match l@1 { List::Cons => { + storage_live(hd@2) + hd@2 := move ((l@1 as variant List::Cons).0) + storage_live(tl@3) + tl@3 := move ((l@1 as variant List::Cons).1) + storage_live(@4) + @4 := move (hd@2) + storage_live(@5) + @5 := move (*(tl@3)) + @0 := (move (@4), move (@5)) + drop[{impl Destruct for List[@TraitClause0]}[@TraitClause0]] @5 + storage_dead(@5) + drop[{built_in impl Destruct for T}] @4 + storage_dead(@4) + drop[{impl Destruct for alloc::boxed::Box[@TraitClause0, @TraitClause1]}[@TraitClause0], Global>[{built_in impl MetaSized for List[@TraitClause0]}, {built_in impl Sized for Global}]] tl@3 + storage_dead(tl@3) + drop[{built_in impl Destruct for T}] hd@2 + storage_dead(hd@2) + drop[{impl Destruct for List[@TraitClause0]}[@TraitClause0]] l@1 + return }, _ => { panic(core::panicking::panic) }, } - storage_live(hd@2) - hd@2 := move ((l@1 as variant List::Cons).0) - storage_live(tl@3) - tl@3 := move ((l@1 as variant List::Cons).1) - storage_live(@4) - @4 := move (hd@2) - storage_live(@5) - @5 := move (*(tl@3)) - @0 := (move (@4), move (@5)) - drop[{impl Destruct for List[@TraitClause0]}[@TraitClause0]] @5 - storage_dead(@5) - drop[{built_in impl Destruct for T}] @4 - storage_dead(@4) - drop[{impl Destruct for alloc::boxed::Box[@TraitClause0, @TraitClause1]}[@TraitClause0], Global>[{built_in impl MetaSized for List[@TraitClause0]}, {built_in impl Sized for Global}]] tl@3 - storage_dead(tl@3) - drop[{built_in impl Destruct for T}] hd@2 - storage_dead(hd@2) - drop[{impl Destruct for List[@TraitClause0]}[@TraitClause0]] l@1 - return } // Full name: test_crate::test_char diff --git a/charon/tests/ui/opaque_attribute.out b/charon/tests/ui/opaque_attribute.out index 4cb096bdc..415b1ccad 100644 --- a/charon/tests/ui/opaque_attribute.out +++ b/charon/tests/ui/opaque_attribute.out @@ -75,6 +75,8 @@ where match *(self@1) { Option::None => { + @0 := const (false) + return }, Option::Some => { storage_live(x@2) @@ -87,8 +89,6 @@ where return }, } - @0 := const (false) - return } // Full name: test_crate::{impl BoolTrait for Option[@TraitClause0]} diff --git a/charon/tests/ui/panics.out b/charon/tests/ui/panics.out index 098d24bc2..6ac8db0fe 100644 --- a/charon/tests/ui/panics.out +++ b/charon/tests/ui/panics.out @@ -141,6 +141,9 @@ fn panic5() storage_live(@1) @1 := const (false) if move (@1) { + storage_dead(@1) + @0 := () + return } else { storage_live(@6) @@ -157,9 +160,6 @@ fn panic5() storage_dead(@3) panic(core::panicking::panic_fmt) } - storage_dead(@1) - @0 := () - return } // Full name: test_crate::panic6 diff --git a/charon/tests/ui/projection-index-from-end.out b/charon/tests/ui/projection-index-from-end.out index f4367df0c..4b370e018 100644 --- a/charon/tests/ui/projection-index-from-end.out +++ b/charon/tests/ui/projection-index-from-end.out @@ -35,25 +35,25 @@ fn slice_pattern_end<'_0>(@1: &'_0 (Slice<()>)) @4 := const (1 : usize) @5 := move (@2) >= move (@4) if move (@5) { + storage_live(_named@6) + storage_live(@7) + @7 := &*(x@1) with_metadata(copy (x@1.metadata)) + storage_live(@8) + @8 := len(*(x@1)) + storage_live(@9) + @9 := copy (@8) ub.- const (1 : usize) + storage_dead(@8) + storage_live(@10) + @10 := @SliceIndexShared<'_, ()>(move (@7), copy (@9)) + _named@6 := &*(@10) + @0 := () + storage_dead(_named@6) + return } else { @0 := () return } - storage_live(_named@6) - storage_live(@7) - @7 := &*(x@1) with_metadata(copy (x@1.metadata)) - storage_live(@8) - @8 := len(*(x@1)) - storage_live(@9) - @9 := copy (@8) ub.- const (1 : usize) - storage_dead(@8) - storage_live(@10) - @10 := @SliceIndexShared<'_, ()>(move (@7), copy (@9)) - _named@6 := &*(@10) - @0 := () - storage_dead(_named@6) - return } diff --git a/charon/tests/ui/ptr-offset.out b/charon/tests/ui/ptr-offset.out index 5e338206c..1a7317e39 100644 --- a/charon/tests/ui/ptr-offset.out +++ b/charon/tests/ui/ptr-offset.out @@ -340,19 +340,19 @@ fn main() @6 := copy (*(@7)) @5 := move (@6) == const (42 : i32) if move (@5) { + storage_dead(@6) + storage_dead(@7) + storage_dead(@5) + @0 := () + storage_dead(ptr@2) + storage_dead(s@1) + return } else { storage_dead(@6) storage_dead(@7) panic(core::panicking::panic) } - storage_dead(@6) - storage_dead(@7) - storage_dead(@5) - @0 := () - storage_dead(ptr@2) - storage_dead(s@1) - return } diff --git a/charon/tests/ui/raw-boxes.out b/charon/tests/ui/raw-boxes.out index 82dc05e80..8f8da5ce4 100644 --- a/charon/tests/ui/raw-boxes.out +++ b/charon/tests/ui/raw-boxes.out @@ -312,6 +312,8 @@ fn core::ptr::alignment::{Alignment}::new_unchecked::precondition_check(@1: usiz @6 := ctpop[{built_in impl Sized for usize}, {impl Copy for usize}](move (align@1)) switch move (@6) { 1 : u32 => { + storage_dead(@6) + return }, _ => { storage_live(@9) @@ -335,8 +337,6 @@ fn core::ptr::alignment::{Alignment}::new_unchecked::precondition_check(@1: usiz @2 := panic_nounwind_fmt<'_>(move (@3), const (false)) }, } - storage_dead(@6) - return } pub fn core::ptr::alignment::{Alignment}::new(@1: usize) -> Option[{built_in impl Sized for Alignment}] @@ -354,6 +354,20 @@ pub fn core::ptr::alignment::{Alignment}::new(@1: usize) -> Option[{b @3 := ctpop[{built_in impl Sized for usize}, {impl Copy for usize}](copy (align@1)) switch move (@3) { 1 : u32 => { + storage_dead(@3) + storage_live(@2) + storage_live(@5) + @5 := ub_checks + if copy (@5) { + @4 := core::ptr::alignment::{Alignment}::new_unchecked::precondition_check(copy (align@1)) + } + else { + } + @2 := transmute(copy (align@1)) + storage_dead(@5) + @0 := Option::Some { 0: move (@2) } + storage_dead(@2) + return }, _ => { storage_dead(@3) @@ -363,20 +377,6 @@ pub fn core::ptr::alignment::{Alignment}::new(@1: usize) -> Option[{b return }, } - storage_dead(@3) - storage_live(@2) - storage_live(@5) - @5 := ub_checks - if copy (@5) { - @4 := core::ptr::alignment::{Alignment}::new_unchecked::precondition_check(copy (align@1)) - } - else { - } - @2 := transmute(copy (align@1)) - storage_dead(@5) - @0 := Option::Some { 0: move (@2) } - storage_dead(@2) - return } // Full name: core::alloc::layout::{Layout}::max_size_for_align @@ -417,6 +417,34 @@ fn is_size_align_valid(@1: usize, @2: usize) -> bool storage_dead(@5) match @4 { Option::Some => { + storage_live(align@3) + align@3 := copy ((@4 as variant Option::Some).0) + storage_dead(@4) + storage_live(@6) + storage_live(@7) + @7 := copy (size@1) + storage_live(@8) + storage_live(@9) + @9 := copy (align@3) + @8 := max_size_for_align(move (@9)) + storage_dead(@9) + @6 := move (@7) > move (@8) + if move (@6) { + storage_dead(@8) + storage_dead(@7) + @0 := const (false) + storage_dead(@6) + storage_dead(align@3) + return + } + else { + storage_dead(@8) + storage_dead(@7) + storage_dead(@6) + @0 := const (true) + storage_dead(align@3) + return + } }, _ => { storage_dead(@4) @@ -424,34 +452,6 @@ fn is_size_align_valid(@1: usize, @2: usize) -> bool return }, } - storage_live(align@3) - align@3 := copy ((@4 as variant Option::Some).0) - storage_dead(@4) - storage_live(@6) - storage_live(@7) - @7 := copy (size@1) - storage_live(@8) - storage_live(@9) - @9 := copy (align@3) - @8 := max_size_for_align(move (@9)) - storage_dead(@9) - @6 := move (@7) > move (@8) - if move (@6) { - } - else { - storage_dead(@8) - storage_dead(@7) - storage_dead(@6) - @0 := const (true) - storage_dead(align@3) - return - } - storage_dead(@8) - storage_dead(@7) - @0 := const (false) - storage_dead(@6) - storage_dead(align@3) - return } // Full name: core::mem::SizedTypeProperties @@ -488,6 +488,8 @@ fn core::alloc::layout::{Layout}::from_size_align_unchecked::precondition_check( storage_live(@3) @3 := is_size_align_valid(move (size@1), move (align@2)) if move (@3) { + storage_dead(@3) + return } else { storage_live(@10) @@ -509,8 +511,6 @@ fn core::alloc::layout::{Layout}::from_size_align_unchecked::precondition_check( storage_dead(@8) @4 := panic_nounwind_fmt<'_>(move (@5), const (false)) } - storage_dead(@3) - return } // Full name: core::intrinsics::size_of @@ -790,6 +790,60 @@ fn core::ptr::write_bytes::precondition_check(@1: *const (), @2: usize, @3: bool @14 := ctpop[{built_in impl Sized for usize}, {impl Copy for usize}](copy (align@2)) switch move (@14) { 1 : u32 => { + loop { + storage_dead(@14) + storage_live(@11) + @12 := transmute<*const (), usize>(copy (addr@1)) + storage_live(@13) + @13 := copy (align@2) wrap.- const (1 : usize) + @11 := copy (@12) & move (@13) + storage_dead(@13) + switch move (@11) { + 0 : usize => { + storage_dead(@11) + if copy (zero_size@3) { + storage_dead(@12) + } + else { + storage_live(@9) + @9 := copy (@12) == const (0 : usize) + @4 := ~(move (@9)) + storage_dead(@9) + storage_dead(@12) + if move (@4) { + } + else { + break 0 + } + } + storage_dead(@4) + return + }, + _ => { + storage_dead(@11) + storage_dead(@12) + }, + } + break 0 + } + storage_live(@23) + storage_live(@24) + @24 := [] + @23 := &@24 + storage_live(@6) + storage_live(@8) + @8 := [const ("unsafe precondition(s) violated: ptr::write_bytes requires that the destination pointer is aligned and non-null\n\nThis indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.")] + pieces@7 := &@8 + storage_live(@17) + @17 := @ArrayToSliceShared<'_, &'_ (Str), 1 : usize>(copy (pieces@7)) + storage_live(@18) + @18 := @ArrayToSliceShared<'_, Argument<'_>, 0 : usize>(move (@23)) + storage_live(@26) + @26 := Option::None { } + @6 := Arguments { pieces: copy (@17), fmt: move (@26), args: copy (@18) } + storage_dead(@18) + storage_dead(@17) + @5 := panic_nounwind_fmt<'_>(move (@6), const (false)) }, _ => { storage_live(@19) @@ -814,58 +868,6 @@ fn core::ptr::write_bytes::precondition_check(@1: *const (), @2: usize, @3: bool panic(core::panicking::panic_fmt) }, } - storage_dead(@14) - storage_live(@11) - @12 := transmute<*const (), usize>(copy (addr@1)) - storage_live(@13) - @13 := copy (align@2) wrap.- const (1 : usize) - @11 := copy (@12) & move (@13) - storage_dead(@13) - switch move (@11) { - 0 : usize => { - storage_dead(@11) - if copy (zero_size@3) { - storage_dead(@12) - storage_dead(@4) - return - } - else { - storage_live(@9) - @9 := copy (@12) == const (0 : usize) - @4 := ~(move (@9)) - storage_dead(@9) - storage_dead(@12) - if move (@4) { - storage_dead(@4) - return - } - else { - } - } - }, - _ => { - storage_dead(@11) - storage_dead(@12) - }, - } - storage_live(@23) - storage_live(@24) - @24 := [] - @23 := &@24 - storage_live(@6) - storage_live(@8) - @8 := [const ("unsafe precondition(s) violated: ptr::write_bytes requires that the destination pointer is aligned and non-null\n\nThis indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.")] - pieces@7 := &@8 - storage_live(@17) - @17 := @ArrayToSliceShared<'_, &'_ (Str), 1 : usize>(copy (pieces@7)) - storage_live(@18) - @18 := @ArrayToSliceShared<'_, Argument<'_>, 0 : usize>(move (@23)) - storage_live(@26) - @26 := Option::None { } - @6 := Arguments { pieces: copy (@17), fmt: move (@26), args: copy (@18) } - storage_dead(@18) - storage_dead(@17) - @5 := panic_nounwind_fmt<'_>(move (@6), const (false)) } // Full name: core::intrinsics::write_bytes @@ -916,6 +918,42 @@ where storage_live(v@10) match self@4 { Result::Ok => { + v@10 := move ((self@4 as variant Result::Ok).0) + @3 := ControlFlow::Continue { 0: copy (v@10) } + storage_dead(v@10) + storage_dead(self@4) + ptr@5 := copy ((@3 as variant ControlFlow::Continue).0) + storage_dead(@3) + storage_live(self@7) + storage_live(self@8) + storage_live(@11) + @12 := transmute>, *mut Slice>(copy (ptr@5)) + @11 := cast<*mut Slice, *const u8>(copy (@12)) + self@8 := NonNull { pointer: copy (@11) } + storage_dead(@11) + self@7 := cast<*mut Slice, *mut u8>(copy (@12)) + storage_dead(self@8) + storage_live(count@9) + count@9 := copy (@12.metadata) + storage_live(@16) + @16 := ub_checks + if copy (@16) { + storage_live(@14) + @14 := cast<*mut Slice, *const ()>(copy (@12)) + storage_live(@15) + @15 := copy (count@9) == const (0 : usize) + @13 := core::ptr::write_bytes::precondition_check(move (@14), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::ALIGN), move (@15)) + storage_dead(@15) + storage_dead(@14) + } + else { + } + @6 := write_bytes[{built_in impl Sized for u8}](move (self@7), const (0 : u8), move (count@9)) + storage_dead(@16) + storage_dead(count@9) + storage_dead(self@7) + @0 := Result::Ok { 0: copy (ptr@5) } + return }, Result::Err => { storage_dead(v@10) @@ -929,42 +967,6 @@ where return }, } - v@10 := move ((self@4 as variant Result::Ok).0) - @3 := ControlFlow::Continue { 0: copy (v@10) } - storage_dead(v@10) - storage_dead(self@4) - ptr@5 := copy ((@3 as variant ControlFlow::Continue).0) - storage_dead(@3) - storage_live(self@7) - storage_live(self@8) - storage_live(@11) - @12 := transmute>, *mut Slice>(copy (ptr@5)) - @11 := cast<*mut Slice, *const u8>(copy (@12)) - self@8 := NonNull { pointer: copy (@11) } - storage_dead(@11) - self@7 := cast<*mut Slice, *mut u8>(copy (@12)) - storage_dead(self@8) - storage_live(count@9) - count@9 := copy (@12.metadata) - storage_live(@16) - @16 := ub_checks - if copy (@16) { - storage_live(@14) - @14 := cast<*mut Slice, *const ()>(copy (@12)) - storage_live(@15) - @15 := copy (count@9) == const (0 : usize) - @13 := core::ptr::write_bytes::precondition_check(move (@14), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::ALIGN), move (@15)) - storage_dead(@15) - storage_dead(@14) - } - else { - } - @6 := write_bytes[{built_in impl Sized for u8}](move (self@7), const (0 : u8), move (count@9)) - storage_dead(@16) - storage_dead(count@9) - storage_dead(self@7) - @0 := Result::Ok { 0: copy (ptr@5) } - return } pub unsafe fn core::alloc::Allocator::deallocate<'_0, Self>(@1: &'_0 (Self), @2: NonNull, @3: Layout) @@ -1086,6 +1088,11 @@ fn runtime(@1: *const (), @2: *const (), @3: usize, @4: usize) -> bool a@16 := cast(copy (@11)) storage_dead(@11) if copy (b@12) { + @17 := cold_path() + storage_dead(a@16) + storage_dead(b@12) + storage_dead(@9) + @7 := panic_nounwind(const ("is_nonoverlapping: `size_of::() * count` overflows a usize")) } else { @9 := Option::Some { 0: copy (a@16) } @@ -1105,11 +1112,6 @@ fn runtime(@1: *const (), @2: *const (), @3: usize, @4: usize) -> bool @0 := move (diff@10) >= copy (size@8) return } - @17 := cold_path() - storage_dead(a@16) - storage_dead(b@12) - storage_dead(@9) - @7 := panic_nounwind(const ("is_nonoverlapping: `size_of::() * count` overflows a usize")) } fn core::ptr::copy_nonoverlapping::precondition_check(@1: *const (), @2: *mut (), @3: usize, @4: usize, @5: usize) @@ -1162,62 +1164,101 @@ fn core::ptr::copy_nonoverlapping::precondition_check(@1: *const (), @2: *mut () let @45: Option<&'_ (Slice)>[{built_in impl Sized for &'_ (Slice)}]; // anonymous local let @46: Option<&'_ (Slice)>[{built_in impl Sized for &'_ (Slice)}]; // anonymous local - storage_live(zero_size@7) - storage_live(ptr@12) - storage_live(@13) - storage_live(pieces@15) - storage_live(@21) - @0 := () - storage_live(@6) - switch copy (count@5) { - 0 : usize => { - }, - _ => { - zero_size@7 := copy (size@3) == const (0 : usize) - storage_live(@8) - storage_live(align@9) - align@9 := copy (align@4) - storage_live(is_zst@10) - is_zst@10 := copy (zero_size@7) - storage_live(@20) - storage_live(@22) - @22 := ctpop[{built_in impl Sized for usize}, {impl Copy for usize}](copy (align@4)) - switch move (@22) { - 1 : u32 => { - }, - _ => { - storage_live(@34) - storage_live(@35) - @35 := [const ("is_aligned_to: align is not a power-of-two")] - @34 := &@35 - storage_live(@36) - storage_live(@37) - @37 := [] - @36 := &@37 - storage_dead(@22) - storage_live(@18) - storage_live(@23) - @23 := @ArrayToSliceShared<'_, &'_ (Str), 1 : usize>(move (@34)) - storage_live(@24) - @24 := @ArrayToSliceShared<'_, Argument<'_>, 0 : usize>(move (@36)) - storage_live(@44) - @44 := Option::None { } - @18 := Arguments { pieces: copy (@23), fmt: move (@44), args: copy (@24) } - storage_dead(@24) - storage_dead(@23) - panic(core::panicking::panic_fmt) - }, - } - storage_dead(@22) - storage_live(@19) - @20 := transmute<*const (), usize>(copy (src@1)) - @21 := copy (align@4) wrap.- const (1 : usize) - @19 := copy (@20) & copy (@21) - switch move (@19) { - 0 : usize => { - storage_dead(@19) - if copy (is_zst@10) { - storage_dead(@20) + loop { + loop { + loop { + loop { + loop { + loop { + storage_live(zero_size@7) + storage_live(ptr@12) + storage_live(@13) + storage_live(pieces@15) + storage_live(@21) + @0 := () + storage_live(@6) + switch copy (count@5) { + 0 : usize => { + zero_size@7 := const (true) + storage_live(@8) + storage_live(align@9) + align@9 := copy (align@4) + storage_live(is_zst@10) + is_zst@10 := copy (zero_size@7) + storage_live(@20) + storage_live(@22) + @22 := ctpop[{built_in impl Sized for usize}, {impl Copy for usize}](copy (align@4)) + switch move (@22) { + 1 : u32 => { + storage_dead(@22) + storage_live(@19) + @20 := transmute<*const (), usize>(copy (src@1)) + @21 := copy (align@4) wrap.- const (1 : usize) + @19 := copy (@20) & copy (@21) + switch move (@19) { + 0 : usize => { + storage_dead(@19) + }, + _ => { + break 1 + }, + } + }, + _ => { + break 5 + }, + } + }, + _ => { + zero_size@7 := copy (size@3) == const (0 : usize) + storage_live(@8) + storage_live(align@9) + align@9 := copy (align@4) + storage_live(is_zst@10) + is_zst@10 := copy (zero_size@7) + storage_live(@20) + storage_live(@22) + @22 := ctpop[{built_in impl Sized for usize}, {impl Copy for usize}](copy (align@4)) + switch move (@22) { + 1 : u32 => { + storage_dead(@22) + storage_live(@19) + @20 := transmute<*const (), usize>(copy (src@1)) + @21 := copy (align@4) wrap.- const (1 : usize) + @19 := copy (@20) & copy (@21) + switch move (@19) { + 0 : usize => { + storage_dead(@19) + if copy (is_zst@10) { + } + else { + storage_live(@17) + @17 := copy (@20) == const (0 : usize) + @8 := ~(move (@17)) + storage_dead(@17) + storage_dead(@20) + if move (@8) { + break 0 + } + else { + break 2 + } + } + }, + _ => { + break 1 + }, + } + }, + _ => { + break 5 + }, + } + }, + } + storage_dead(@20) + break 0 + } storage_dead(is_zst@10) storage_dead(align@9) storage_live(@11) @@ -1227,6 +1268,48 @@ fn core::ptr::copy_nonoverlapping::precondition_check(@1: *const (), @2: *mut () @29 := ctpop[{built_in impl Sized for usize}, {impl Copy for usize}](move (align@4)) switch move (@29) { 1 : u32 => { + loop { + storage_dead(@29) + storage_live(@27) + @28 := transmute<*mut (), usize>(copy (dst@2)) + @27 := copy (@28) & copy (@21) + switch move (@27) { + 0 : usize => { + storage_dead(@27) + if copy (zero_size@7) { + storage_dead(@28) + } + else { + storage_live(@25) + @25 := copy (@28) == const (0 : usize) + @11 := ~(move (@25)) + storage_dead(@25) + storage_dead(@28) + if move (@11) { + } + else { + break 0 + } + } + @6 := runtime(move (src@1), move (ptr@12), move (size@3), move (count@5)) + storage_dead(@11) + storage_dead(@8) + if move (@6) { + storage_dead(@6) + return + } + else { + break 4 + } + }, + _ => { + storage_dead(@27) + storage_dead(@28) + }, + } + break 0 + } + break 2 }, _ => { storage_live(@40) @@ -1251,499 +1334,60 @@ fn core::ptr::copy_nonoverlapping::precondition_check(@1: *const (), @2: *mut () panic(core::panicking::panic_fmt) }, } - storage_dead(@29) - storage_live(@27) - @28 := transmute<*mut (), usize>(copy (dst@2)) - @27 := copy (@28) & copy (@21) - switch move (@27) { - 0 : usize => { - storage_dead(@27) - if copy (zero_size@7) { - storage_dead(@28) - @6 := runtime(move (src@1), move (ptr@12), move (size@3), move (count@5)) - storage_dead(@11) - storage_dead(@8) - if move (@6) { - storage_dead(@6) - return - } - else { - storage_live(@38) - storage_live(@39) - @39 := [] - @38 := &@39 - storage_live(@14) - storage_live(@16) - @16 := [const ("unsafe precondition(s) violated: ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null and the specified memory ranges do not overlap\n\nThis indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.")] - pieces@15 := &@16 - storage_live(@32) - @32 := @ArrayToSliceShared<'_, &'_ (Str), 1 : usize>(copy (pieces@15)) - storage_live(@33) - @33 := @ArrayToSliceShared<'_, Argument<'_>, 0 : usize>(move (@38)) - storage_live(@45) - @45 := Option::None { } - @14 := Arguments { pieces: copy (@32), fmt: move (@45), args: copy (@33) } - storage_dead(@33) - storage_dead(@32) - @13 := panic_nounwind_fmt<'_>(move (@14), const (false)) - } - } - else { - storage_live(@25) - @25 := copy (@28) == const (0 : usize) - @11 := ~(move (@25)) - storage_dead(@25) - storage_dead(@28) - if move (@11) { - @6 := runtime(move (src@1), move (ptr@12), move (size@3), move (count@5)) - storage_dead(@11) - storage_dead(@8) - if move (@6) { - storage_dead(@6) - return - } - else { - storage_live(@38) - storage_live(@39) - @39 := [] - @38 := &@39 - storage_live(@14) - storage_live(@16) - @16 := [const ("unsafe precondition(s) violated: ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null and the specified memory ranges do not overlap\n\nThis indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.")] - pieces@15 := &@16 - storage_live(@32) - @32 := @ArrayToSliceShared<'_, &'_ (Str), 1 : usize>(copy (pieces@15)) - storage_live(@33) - @33 := @ArrayToSliceShared<'_, Argument<'_>, 0 : usize>(move (@38)) - storage_live(@45) - @45 := Option::None { } - @14 := Arguments { pieces: copy (@32), fmt: move (@45), args: copy (@33) } - storage_dead(@33) - storage_dead(@32) - @13 := panic_nounwind_fmt<'_>(move (@14), const (false)) - } - } - else { - storage_dead(@11) - storage_dead(@8) - storage_live(@38) - storage_live(@39) - @39 := [] - @38 := &@39 - storage_live(@14) - storage_live(@16) - @16 := [const ("unsafe precondition(s) violated: ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null and the specified memory ranges do not overlap\n\nThis indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.")] - pieces@15 := &@16 - storage_live(@32) - @32 := @ArrayToSliceShared<'_, &'_ (Str), 1 : usize>(copy (pieces@15)) - storage_live(@33) - @33 := @ArrayToSliceShared<'_, Argument<'_>, 0 : usize>(move (@38)) - storage_live(@45) - @45 := Option::None { } - @14 := Arguments { pieces: copy (@32), fmt: move (@45), args: copy (@33) } - storage_dead(@33) - storage_dead(@32) - @13 := panic_nounwind_fmt<'_>(move (@14), const (false)) - } - } - }, - _ => { - storage_dead(@27) - storage_dead(@28) - storage_dead(@11) - storage_dead(@8) - storage_live(@38) - storage_live(@39) - @39 := [] - @38 := &@39 - storage_live(@14) - storage_live(@16) - @16 := [const ("unsafe precondition(s) violated: ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null and the specified memory ranges do not overlap\n\nThis indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.")] - pieces@15 := &@16 - storage_live(@32) - @32 := @ArrayToSliceShared<'_, &'_ (Str), 1 : usize>(copy (pieces@15)) - storage_live(@33) - @33 := @ArrayToSliceShared<'_, Argument<'_>, 0 : usize>(move (@38)) - storage_live(@45) - @45 := Option::None { } - @14 := Arguments { pieces: copy (@32), fmt: move (@45), args: copy (@33) } - storage_dead(@33) - storage_dead(@32) - @13 := panic_nounwind_fmt<'_>(move (@14), const (false)) - }, - } - } - else { - storage_live(@17) - @17 := copy (@20) == const (0 : usize) - @8 := ~(move (@17)) - storage_dead(@17) - storage_dead(@20) - if move (@8) { - storage_dead(is_zst@10) - storage_dead(align@9) - storage_live(@11) - ptr@12 := cast<*mut (), *const ()>(copy (dst@2)) - storage_live(@28) - storage_live(@29) - @29 := ctpop[{built_in impl Sized for usize}, {impl Copy for usize}](move (align@4)) - switch move (@29) { - 1 : u32 => { - }, - _ => { - storage_live(@40) - storage_live(@41) - @41 := [const ("is_aligned_to: align is not a power-of-two")] - @40 := &@41 - storage_live(@42) - storage_live(@43) - @43 := [] - @42 := &@43 - storage_dead(@29) - storage_live(@26) - storage_live(@30) - @30 := @ArrayToSliceShared<'_, &'_ (Str), 1 : usize>(move (@40)) - storage_live(@31) - @31 := @ArrayToSliceShared<'_, Argument<'_>, 0 : usize>(move (@42)) - storage_live(@46) - @46 := Option::None { } - @26 := Arguments { pieces: copy (@30), fmt: move (@46), args: copy (@31) } - storage_dead(@31) - storage_dead(@30) - panic(core::panicking::panic_fmt) - }, - } - storage_dead(@29) - storage_live(@27) - @28 := transmute<*mut (), usize>(copy (dst@2)) - @27 := copy (@28) & copy (@21) - switch move (@27) { - 0 : usize => { - storage_dead(@27) - if copy (zero_size@7) { - storage_dead(@28) - @6 := runtime(move (src@1), move (ptr@12), move (size@3), move (count@5)) - storage_dead(@11) - storage_dead(@8) - if move (@6) { - storage_dead(@6) - return - } - else { - storage_live(@38) - storage_live(@39) - @39 := [] - @38 := &@39 - storage_live(@14) - storage_live(@16) - @16 := [const ("unsafe precondition(s) violated: ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null and the specified memory ranges do not overlap\n\nThis indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.")] - pieces@15 := &@16 - storage_live(@32) - @32 := @ArrayToSliceShared<'_, &'_ (Str), 1 : usize>(copy (pieces@15)) - storage_live(@33) - @33 := @ArrayToSliceShared<'_, Argument<'_>, 0 : usize>(move (@38)) - storage_live(@45) - @45 := Option::None { } - @14 := Arguments { pieces: copy (@32), fmt: move (@45), args: copy (@33) } - storage_dead(@33) - storage_dead(@32) - @13 := panic_nounwind_fmt<'_>(move (@14), const (false)) - } - } - else { - storage_live(@25) - @25 := copy (@28) == const (0 : usize) - @11 := ~(move (@25)) - storage_dead(@25) - storage_dead(@28) - if move (@11) { - @6 := runtime(move (src@1), move (ptr@12), move (size@3), move (count@5)) - storage_dead(@11) - storage_dead(@8) - if move (@6) { - storage_dead(@6) - return - } - else { - storage_live(@38) - storage_live(@39) - @39 := [] - @38 := &@39 - storage_live(@14) - storage_live(@16) - @16 := [const ("unsafe precondition(s) violated: ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null and the specified memory ranges do not overlap\n\nThis indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.")] - pieces@15 := &@16 - storage_live(@32) - @32 := @ArrayToSliceShared<'_, &'_ (Str), 1 : usize>(copy (pieces@15)) - storage_live(@33) - @33 := @ArrayToSliceShared<'_, Argument<'_>, 0 : usize>(move (@38)) - storage_live(@45) - @45 := Option::None { } - @14 := Arguments { pieces: copy (@32), fmt: move (@45), args: copy (@33) } - storage_dead(@33) - storage_dead(@32) - @13 := panic_nounwind_fmt<'_>(move (@14), const (false)) - } - } - else { - storage_dead(@11) - storage_dead(@8) - storage_live(@38) - storage_live(@39) - @39 := [] - @38 := &@39 - storage_live(@14) - storage_live(@16) - @16 := [const ("unsafe precondition(s) violated: ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null and the specified memory ranges do not overlap\n\nThis indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.")] - pieces@15 := &@16 - storage_live(@32) - @32 := @ArrayToSliceShared<'_, &'_ (Str), 1 : usize>(copy (pieces@15)) - storage_live(@33) - @33 := @ArrayToSliceShared<'_, Argument<'_>, 0 : usize>(move (@38)) - storage_live(@45) - @45 := Option::None { } - @14 := Arguments { pieces: copy (@32), fmt: move (@45), args: copy (@33) } - storage_dead(@33) - storage_dead(@32) - @13 := panic_nounwind_fmt<'_>(move (@14), const (false)) - } - } - }, - _ => { - storage_dead(@27) - storage_dead(@28) - storage_dead(@11) - storage_dead(@8) - storage_live(@38) - storage_live(@39) - @39 := [] - @38 := &@39 - storage_live(@14) - storage_live(@16) - @16 := [const ("unsafe precondition(s) violated: ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null and the specified memory ranges do not overlap\n\nThis indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.")] - pieces@15 := &@16 - storage_live(@32) - @32 := @ArrayToSliceShared<'_, &'_ (Str), 1 : usize>(copy (pieces@15)) - storage_live(@33) - @33 := @ArrayToSliceShared<'_, Argument<'_>, 0 : usize>(move (@38)) - storage_live(@45) - @45 := Option::None { } - @14 := Arguments { pieces: copy (@32), fmt: move (@45), args: copy (@33) } - storage_dead(@33) - storage_dead(@32) - @13 := panic_nounwind_fmt<'_>(move (@14), const (false)) - }, - } - } - else { - storage_dead(is_zst@10) - storage_dead(align@9) - storage_dead(@11) - storage_dead(@8) - storage_live(@38) - storage_live(@39) - @39 := [] - @38 := &@39 - storage_live(@14) - storage_live(@16) - @16 := [const ("unsafe precondition(s) violated: ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null and the specified memory ranges do not overlap\n\nThis indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.")] - pieces@15 := &@16 - storage_live(@32) - @32 := @ArrayToSliceShared<'_, &'_ (Str), 1 : usize>(copy (pieces@15)) - storage_live(@33) - @33 := @ArrayToSliceShared<'_, Argument<'_>, 0 : usize>(move (@38)) - storage_live(@45) - @45 := Option::None { } - @14 := Arguments { pieces: copy (@32), fmt: move (@45), args: copy (@33) } - storage_dead(@33) - storage_dead(@32) - @13 := panic_nounwind_fmt<'_>(move (@14), const (false)) - } + break 0 } - }, - _ => { storage_dead(@19) storage_dead(@20) - storage_dead(is_zst@10) - storage_dead(align@9) - storage_dead(@11) - storage_dead(@8) - storage_live(@38) - storage_live(@39) - @39 := [] - @38 := &@39 - storage_live(@14) - storage_live(@16) - @16 := [const ("unsafe precondition(s) violated: ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null and the specified memory ranges do not overlap\n\nThis indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.")] - pieces@15 := &@16 - storage_live(@32) - @32 := @ArrayToSliceShared<'_, &'_ (Str), 1 : usize>(copy (pieces@15)) - storage_live(@33) - @33 := @ArrayToSliceShared<'_, Argument<'_>, 0 : usize>(move (@38)) - storage_live(@45) - @45 := Option::None { } - @14 := Arguments { pieces: copy (@32), fmt: move (@45), args: copy (@33) } - storage_dead(@33) - storage_dead(@32) - @13 := panic_nounwind_fmt<'_>(move (@14), const (false)) - }, + break 0 + } + storage_dead(is_zst@10) + storage_dead(align@9) + break 0 } - }, - } - zero_size@7 := const (true) - storage_live(@8) - storage_live(align@9) - align@9 := copy (align@4) - storage_live(is_zst@10) - is_zst@10 := copy (zero_size@7) - storage_live(@20) - storage_live(@22) - @22 := ctpop[{built_in impl Sized for usize}, {impl Copy for usize}](copy (align@4)) - switch move (@22) { - 1 : u32 => { - }, - _ => { - storage_live(@34) - storage_live(@35) - @35 := [const ("is_aligned_to: align is not a power-of-two")] - @34 := &@35 - storage_live(@36) - storage_live(@37) - @37 := [] - @36 := &@37 - storage_dead(@22) - storage_live(@18) - storage_live(@23) - @23 := @ArrayToSliceShared<'_, &'_ (Str), 1 : usize>(move (@34)) - storage_live(@24) - @24 := @ArrayToSliceShared<'_, Argument<'_>, 0 : usize>(move (@36)) - storage_live(@44) - @44 := Option::None { } - @18 := Arguments { pieces: copy (@23), fmt: move (@44), args: copy (@24) } - storage_dead(@24) - storage_dead(@23) - panic(core::panicking::panic_fmt) - }, + storage_dead(@11) + storage_dead(@8) + break 0 + } + storage_live(@38) + storage_live(@39) + @39 := [] + @38 := &@39 + storage_live(@14) + storage_live(@16) + @16 := [const ("unsafe precondition(s) violated: ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null and the specified memory ranges do not overlap\n\nThis indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.")] + pieces@15 := &@16 + storage_live(@32) + @32 := @ArrayToSliceShared<'_, &'_ (Str), 1 : usize>(copy (pieces@15)) + storage_live(@33) + @33 := @ArrayToSliceShared<'_, Argument<'_>, 0 : usize>(move (@38)) + storage_live(@45) + @45 := Option::None { } + @14 := Arguments { pieces: copy (@32), fmt: move (@45), args: copy (@33) } + storage_dead(@33) + storage_dead(@32) + @13 := panic_nounwind_fmt<'_>(move (@14), const (false)) + break 0 } + storage_live(@34) + storage_live(@35) + @35 := [const ("is_aligned_to: align is not a power-of-two")] + @34 := &@35 + storage_live(@36) + storage_live(@37) + @37 := [] + @36 := &@37 storage_dead(@22) - storage_live(@19) - @20 := transmute<*const (), usize>(copy (src@1)) - @21 := copy (align@4) wrap.- const (1 : usize) - @19 := copy (@20) & copy (@21) - switch move (@19) { - 0 : usize => { - storage_dead(@19) - storage_dead(@20) - storage_dead(is_zst@10) - storage_dead(align@9) - storage_live(@11) - ptr@12 := cast<*mut (), *const ()>(copy (dst@2)) - storage_live(@28) - storage_live(@29) - @29 := ctpop[{built_in impl Sized for usize}, {impl Copy for usize}](move (align@4)) - switch move (@29) { - 1 : u32 => { - }, - _ => { - storage_live(@40) - storage_live(@41) - @41 := [const ("is_aligned_to: align is not a power-of-two")] - @40 := &@41 - storage_live(@42) - storage_live(@43) - @43 := [] - @42 := &@43 - storage_dead(@29) - storage_live(@26) - storage_live(@30) - @30 := @ArrayToSliceShared<'_, &'_ (Str), 1 : usize>(move (@40)) - storage_live(@31) - @31 := @ArrayToSliceShared<'_, Argument<'_>, 0 : usize>(move (@42)) - storage_live(@46) - @46 := Option::None { } - @26 := Arguments { pieces: copy (@30), fmt: move (@46), args: copy (@31) } - storage_dead(@31) - storage_dead(@30) - panic(core::panicking::panic_fmt) - }, - } - storage_dead(@29) - storage_live(@27) - @28 := transmute<*mut (), usize>(copy (dst@2)) - @27 := copy (@28) & copy (@21) - switch move (@27) { - 0 : usize => { - storage_dead(@27) - if copy (zero_size@7) { - storage_dead(@28) - @6 := runtime(move (src@1), move (ptr@12), move (size@3), move (count@5)) - storage_dead(@11) - storage_dead(@8) - if move (@6) { - storage_dead(@6) - return - } - else { - } - } - else { - storage_live(@25) - @25 := copy (@28) == const (0 : usize) - @11 := ~(move (@25)) - storage_dead(@25) - storage_dead(@28) - if move (@11) { - @6 := runtime(move (src@1), move (ptr@12), move (size@3), move (count@5)) - storage_dead(@11) - storage_dead(@8) - if move (@6) { - storage_dead(@6) - return - } - else { - } - } - else { - storage_dead(@11) - storage_dead(@8) - } - } - }, - _ => { - storage_dead(@27) - storage_dead(@28) - storage_dead(@11) - storage_dead(@8) - }, - } - }, - _ => { - storage_dead(@19) - storage_dead(@20) - storage_dead(is_zst@10) - storage_dead(align@9) - storage_dead(@11) - storage_dead(@8) - }, - } - storage_live(@38) - storage_live(@39) - @39 := [] - @38 := &@39 - storage_live(@14) - storage_live(@16) - @16 := [const ("unsafe precondition(s) violated: ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null and the specified memory ranges do not overlap\n\nThis indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.")] - pieces@15 := &@16 - storage_live(@32) - @32 := @ArrayToSliceShared<'_, &'_ (Str), 1 : usize>(copy (pieces@15)) - storage_live(@33) - @33 := @ArrayToSliceShared<'_, Argument<'_>, 0 : usize>(move (@38)) - storage_live(@45) - @45 := Option::None { } - @14 := Arguments { pieces: copy (@32), fmt: move (@45), args: copy (@33) } - storage_dead(@33) - storage_dead(@32) - @13 := panic_nounwind_fmt<'_>(move (@14), const (false)) + storage_live(@18) + storage_live(@23) + @23 := @ArrayToSliceShared<'_, &'_ (Str), 1 : usize>(move (@34)) + storage_live(@24) + @24 := @ArrayToSliceShared<'_, Argument<'_>, 0 : usize>(move (@36)) + storage_live(@44) + @44 := Option::None { } + @18 := Arguments { pieces: copy (@23), fmt: move (@44), args: copy (@24) } + storage_dead(@24) + storage_dead(@23) + panic(core::panicking::panic_fmt) } pub unsafe fn core::alloc::Allocator::grow<'_0, Self>(@1: &'_0 (Self), @2: NonNull, @3: Layout, @4: Layout) -> Result>, AllocError>[{built_in impl Sized for NonNull>}, {built_in impl Sized for AllocError}] @@ -1781,6 +1425,40 @@ where storage_live(v@12) match self@6 { Result::Ok => { + v@12 := move ((self@6 as variant Result::Ok).0) + @5 := ControlFlow::Continue { 0: copy (v@12) } + storage_dead(v@12) + storage_dead(self@6) + new_ptr@7 := copy ((@5 as variant ControlFlow::Continue).0) + storage_dead(@5) + storage_live(src@8) + src@8 := transmute, *const u8>(copy (ptr@2)) + storage_live(dst@9) + @13 := transmute>, *mut Slice>(copy (new_ptr@7)) + dst@9 := cast<*mut Slice, *mut u8>(copy (@13)) + storage_live(count@10) + count@10 := copy ((old_layout@3).size) + storage_live(@17) + @17 := ub_checks + if copy (@17) { + storage_live(@15) + @15 := transmute, *const ()>(copy (ptr@2)) + storage_live(@16) + @16 := cast<*mut Slice, *mut ()>(copy (@13)) + @14 := core::ptr::copy_nonoverlapping::precondition_check(move (@15), move (@16), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::SIZE), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::ALIGN), copy (count@10)) + storage_dead(@16) + storage_dead(@15) + } + else { + } + copy_nonoverlapping(copy (src@8), copy (dst@9), copy (count@10)) + storage_dead(@17) + storage_dead(count@10) + storage_dead(dst@9) + storage_dead(src@8) + @11 := @TraitClause0::deallocate<'_>(move (self@1), move (ptr@2), move (old_layout@3)) + @0 := Result::Ok { 0: copy (new_ptr@7) } + return }, Result::Err => { storage_dead(v@12) @@ -1794,40 +1472,6 @@ where return }, } - v@12 := move ((self@6 as variant Result::Ok).0) - @5 := ControlFlow::Continue { 0: copy (v@12) } - storage_dead(v@12) - storage_dead(self@6) - new_ptr@7 := copy ((@5 as variant ControlFlow::Continue).0) - storage_dead(@5) - storage_live(src@8) - src@8 := transmute, *const u8>(copy (ptr@2)) - storage_live(dst@9) - @13 := transmute>, *mut Slice>(copy (new_ptr@7)) - dst@9 := cast<*mut Slice, *mut u8>(copy (@13)) - storage_live(count@10) - count@10 := copy ((old_layout@3).size) - storage_live(@17) - @17 := ub_checks - if copy (@17) { - storage_live(@15) - @15 := transmute, *const ()>(copy (ptr@2)) - storage_live(@16) - @16 := cast<*mut Slice, *mut ()>(copy (@13)) - @14 := core::ptr::copy_nonoverlapping::precondition_check(move (@15), move (@16), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::SIZE), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::ALIGN), copy (count@10)) - storage_dead(@16) - storage_dead(@15) - } - else { - } - copy_nonoverlapping(copy (src@8), copy (dst@9), copy (count@10)) - storage_dead(@17) - storage_dead(count@10) - storage_dead(dst@9) - storage_dead(src@8) - @11 := @TraitClause0::deallocate<'_>(move (self@1), move (ptr@2), move (old_layout@3)) - @0 := Result::Ok { 0: copy (new_ptr@7) } - return } pub unsafe fn core::alloc::Allocator::grow_zeroed<'_0, Self>(@1: &'_0 (Self), @2: NonNull, @3: Layout, @4: Layout) -> Result>, AllocError>[{built_in impl Sized for NonNull>}, {built_in impl Sized for AllocError}] @@ -1865,6 +1509,40 @@ where storage_live(v@12) match self@6 { Result::Ok => { + v@12 := move ((self@6 as variant Result::Ok).0) + @5 := ControlFlow::Continue { 0: copy (v@12) } + storage_dead(v@12) + storage_dead(self@6) + new_ptr@7 := copy ((@5 as variant ControlFlow::Continue).0) + storage_dead(@5) + storage_live(src@8) + src@8 := transmute, *const u8>(copy (ptr@2)) + storage_live(dst@9) + @13 := transmute>, *mut Slice>(copy (new_ptr@7)) + dst@9 := cast<*mut Slice, *mut u8>(copy (@13)) + storage_live(count@10) + count@10 := copy ((old_layout@3).size) + storage_live(@17) + @17 := ub_checks + if copy (@17) { + storage_live(@15) + @15 := transmute, *const ()>(copy (ptr@2)) + storage_live(@16) + @16 := cast<*mut Slice, *mut ()>(copy (@13)) + @14 := core::ptr::copy_nonoverlapping::precondition_check(move (@15), move (@16), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::SIZE), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::ALIGN), copy (count@10)) + storage_dead(@16) + storage_dead(@15) + } + else { + } + copy_nonoverlapping(copy (src@8), copy (dst@9), copy (count@10)) + storage_dead(@17) + storage_dead(count@10) + storage_dead(dst@9) + storage_dead(src@8) + @11 := @TraitClause0::deallocate<'_>(move (self@1), move (ptr@2), move (old_layout@3)) + @0 := Result::Ok { 0: copy (new_ptr@7) } + return }, Result::Err => { storage_dead(v@12) @@ -1878,40 +1556,6 @@ where return }, } - v@12 := move ((self@6 as variant Result::Ok).0) - @5 := ControlFlow::Continue { 0: copy (v@12) } - storage_dead(v@12) - storage_dead(self@6) - new_ptr@7 := copy ((@5 as variant ControlFlow::Continue).0) - storage_dead(@5) - storage_live(src@8) - src@8 := transmute, *const u8>(copy (ptr@2)) - storage_live(dst@9) - @13 := transmute>, *mut Slice>(copy (new_ptr@7)) - dst@9 := cast<*mut Slice, *mut u8>(copy (@13)) - storage_live(count@10) - count@10 := copy ((old_layout@3).size) - storage_live(@17) - @17 := ub_checks - if copy (@17) { - storage_live(@15) - @15 := transmute, *const ()>(copy (ptr@2)) - storage_live(@16) - @16 := cast<*mut Slice, *mut ()>(copy (@13)) - @14 := core::ptr::copy_nonoverlapping::precondition_check(move (@15), move (@16), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::SIZE), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::ALIGN), copy (count@10)) - storage_dead(@16) - storage_dead(@15) - } - else { - } - copy_nonoverlapping(copy (src@8), copy (dst@9), copy (count@10)) - storage_dead(@17) - storage_dead(count@10) - storage_dead(dst@9) - storage_dead(src@8) - @11 := @TraitClause0::deallocate<'_>(move (self@1), move (ptr@2), move (old_layout@3)) - @0 := Result::Ok { 0: copy (new_ptr@7) } - return } pub unsafe fn core::alloc::Allocator::shrink<'_0, Self>(@1: &'_0 (Self), @2: NonNull, @3: Layout, @4: Layout) -> Result>, AllocError>[{built_in impl Sized for NonNull>}, {built_in impl Sized for AllocError}] @@ -1949,6 +1593,40 @@ where storage_live(v@12) match self@6 { Result::Ok => { + v@12 := move ((self@6 as variant Result::Ok).0) + @5 := ControlFlow::Continue { 0: copy (v@12) } + storage_dead(v@12) + storage_dead(self@6) + new_ptr@7 := copy ((@5 as variant ControlFlow::Continue).0) + storage_dead(@5) + storage_live(src@8) + src@8 := transmute, *const u8>(copy (ptr@2)) + storage_live(dst@9) + @13 := transmute>, *mut Slice>(copy (new_ptr@7)) + dst@9 := cast<*mut Slice, *mut u8>(copy (@13)) + storage_live(count@10) + count@10 := copy ((new_layout@4).size) + storage_live(@17) + @17 := ub_checks + if copy (@17) { + storage_live(@15) + @15 := transmute, *const ()>(copy (ptr@2)) + storage_live(@16) + @16 := cast<*mut Slice, *mut ()>(copy (@13)) + @14 := core::ptr::copy_nonoverlapping::precondition_check(move (@15), move (@16), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::SIZE), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::ALIGN), copy (count@10)) + storage_dead(@16) + storage_dead(@15) + } + else { + } + copy_nonoverlapping(copy (src@8), copy (dst@9), copy (count@10)) + storage_dead(@17) + storage_dead(count@10) + storage_dead(dst@9) + storage_dead(src@8) + @11 := @TraitClause0::deallocate<'_>(move (self@1), move (ptr@2), move (old_layout@3)) + @0 := Result::Ok { 0: copy (new_ptr@7) } + return }, Result::Err => { storage_dead(v@12) @@ -1962,40 +1640,6 @@ where return }, } - v@12 := move ((self@6 as variant Result::Ok).0) - @5 := ControlFlow::Continue { 0: copy (v@12) } - storage_dead(v@12) - storage_dead(self@6) - new_ptr@7 := copy ((@5 as variant ControlFlow::Continue).0) - storage_dead(@5) - storage_live(src@8) - src@8 := transmute, *const u8>(copy (ptr@2)) - storage_live(dst@9) - @13 := transmute>, *mut Slice>(copy (new_ptr@7)) - dst@9 := cast<*mut Slice, *mut u8>(copy (@13)) - storage_live(count@10) - count@10 := copy ((new_layout@4).size) - storage_live(@17) - @17 := ub_checks - if copy (@17) { - storage_live(@15) - @15 := transmute, *const ()>(copy (ptr@2)) - storage_live(@16) - @16 := cast<*mut Slice, *mut ()>(copy (@13)) - @14 := core::ptr::copy_nonoverlapping::precondition_check(move (@15), move (@16), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::SIZE), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::ALIGN), copy (count@10)) - storage_dead(@16) - storage_dead(@15) - } - else { - } - copy_nonoverlapping(copy (src@8), copy (dst@9), copy (count@10)) - storage_dead(@17) - storage_dead(count@10) - storage_dead(dst@9) - storage_dead(src@8) - @11 := @TraitClause0::deallocate<'_>(move (self@1), move (ptr@2), move (old_layout@3)) - @0 := Result::Ok { 0: copy (new_ptr@7) } - return } pub fn core::alloc::Allocator::by_ref<'_0, Self>(@1: &'_0 (Self)) -> &'_0 (Self) @@ -2161,31 +1805,31 @@ fn core::ptr::non_null::{NonNull}::new_unchecked::precondition_check(@1: *mut @6 := transmute<*mut (), usize>(copy (ptr@1)) switch move (@6) { 0 : usize => { + storage_live(@9) + storage_live(@10) + @10 := [] + @9 := &@10 + storage_dead(@6) + storage_live(@3) + storage_live(@5) + @5 := [const ("unsafe precondition(s) violated: NonNull::new_unchecked requires that the pointer is non-null\n\nThis indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.")] + pieces@4 := &@5 + storage_live(@7) + @7 := @ArrayToSliceShared<'_, &'_ (Str), 1 : usize>(copy (pieces@4)) + storage_live(@8) + @8 := @ArrayToSliceShared<'_, Argument<'_>, 0 : usize>(move (@9)) + storage_live(@11) + @11 := Option::None { } + @3 := Arguments { pieces: copy (@7), fmt: move (@11), args: copy (@8) } + storage_dead(@8) + storage_dead(@7) + @2 := panic_nounwind_fmt<'_>(move (@3), const (false)) }, _ => { storage_dead(@6) return }, } - storage_live(@9) - storage_live(@10) - @10 := [] - @9 := &@10 - storage_dead(@6) - storage_live(@3) - storage_live(@5) - @5 := [const ("unsafe precondition(s) violated: NonNull::new_unchecked requires that the pointer is non-null\n\nThis indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.")] - pieces@4 := &@5 - storage_live(@7) - @7 := @ArrayToSliceShared<'_, &'_ (Str), 1 : usize>(copy (pieces@4)) - storage_live(@8) - @8 := @ArrayToSliceShared<'_, Argument<'_>, 0 : usize>(move (@9)) - storage_live(@11) - @11 := Option::None { } - @3 := Arguments { pieces: copy (@7), fmt: move (@11), args: copy (@8) } - storage_dead(@8) - storage_dead(@7) - @2 := panic_nounwind_fmt<'_>(move (@3), const (false)) } fn core::hint::assert_unchecked::precondition_check(@1: bool) @@ -2206,6 +1850,7 @@ fn core::hint::assert_unchecked::precondition_check(@1: bool) storage_live(pieces@4) @0 := () if copy (cond@1) { + return } else { storage_live(@8) @@ -2227,7 +1872,6 @@ fn core::hint::assert_unchecked::precondition_check(@1: bool) storage_dead(@6) @2 := panic_nounwind_fmt<'_>(move (@3), const (false)) } - return } // Full name: alloc::alloc::__rust_alloc @@ -2318,6 +1962,41 @@ fn alloc_impl<'_0>(@1: &'_0 (Global), @2: Layout, @3: bool) -> Result { + storage_live(@5) + storage_live(data@6) + storage_live(@14) + @14 := copy ((layout@2).align) + @13 := transmute[{built_in impl Sized for usize}, {impl ZeroablePrimitive for usize}]>(copy (@14)) + storage_dead(@14) + storage_live(@15) + @15 := transmute[{built_in impl Sized for usize}, {impl ZeroablePrimitive for usize}], *const u8>(copy (@13)) + data@6 := NonNull { pointer: copy (@15) } + storage_dead(@15) + storage_live(ptr@16) + storage_live(data@17) + data@17 := transmute[{built_in impl Sized for usize}, {impl ZeroablePrimitive for usize}], *mut u8>(copy (@13)) + ptr@16 := @PtrFromPartsMut<'_, Slice>(copy (data@17), const (0 : usize)) + storage_dead(data@17) + storage_live(@20) + storage_live(@21) + @21 := ub_checks + if copy (@21) { + storage_live(@19) + @19 := transmute[{built_in impl Sized for usize}, {impl ZeroablePrimitive for usize}], *mut ()>(copy (@13)) + @18 := core::ptr::non_null::{NonNull}::new_unchecked::precondition_check(move (@19)) + storage_dead(@19) + } + else { + } + @20 := cast<*mut Slice, *const Slice>(copy (ptr@16)) + @5 := NonNull { pointer: copy (@20) } + storage_dead(@21) + storage_dead(@20) + storage_dead(ptr@16) + storage_dead(data@6) + @0 := Result::Ok { 0: move (@5) } + storage_dead(@5) + return }, _ => { if copy (zeroed@3) { @@ -2348,6 +2027,28 @@ fn alloc_impl<'_0>(@1: &'_0 (Global), @2: Layout, @3: bool) -> Result(copy (raw_ptr@7)) switch move (@30) { 0 : usize => { + storage_dead(@30) + storage_live(@42) + @42 := Option::None { } + self@10 := move (@42) + storage_live(v@34) + storage_live(@43) + @43 := AllocError { } + storage_live(@44) + @44 := Result::Err { 0: move (@43) } + self@9 := move (@44) + storage_dead(v@34) + storage_dead(self@10) + storage_live(v@35) + storage_dead(v@35) + storage_dead(self@9) + storage_live(@45) + @45 := AllocError { } + storage_live(@46) + @46 := Result::Err { 0: move (@45) } + @0 := move (@46) + storage_dead(@8) + return }, _ => { storage_dead(@30) @@ -2405,65 +2106,8 @@ fn alloc_impl<'_0>(@1: &'_0 (Global), @2: Layout, @3: bool) -> Result[{built_in impl Sized for usize}, {impl ZeroablePrimitive for usize}]>(copy (@14)) - storage_dead(@14) - storage_live(@15) - @15 := transmute[{built_in impl Sized for usize}, {impl ZeroablePrimitive for usize}], *const u8>(copy (@13)) - data@6 := NonNull { pointer: copy (@15) } - storage_dead(@15) - storage_live(ptr@16) - storage_live(data@17) - data@17 := transmute[{built_in impl Sized for usize}, {impl ZeroablePrimitive for usize}], *mut u8>(copy (@13)) - ptr@16 := @PtrFromPartsMut<'_, Slice>(copy (data@17), const (0 : usize)) - storage_dead(data@17) - storage_live(@20) - storage_live(@21) - @21 := ub_checks - if copy (@21) { - storage_live(@19) - @19 := transmute[{built_in impl Sized for usize}, {impl ZeroablePrimitive for usize}], *mut ()>(copy (@13)) - @18 := core::ptr::non_null::{NonNull}::new_unchecked::precondition_check(move (@19)) - storage_dead(@19) - } - else { - } - @20 := cast<*mut Slice, *const Slice>(copy (ptr@16)) - @5 := NonNull { pointer: copy (@20) } - storage_dead(@21) - storage_dead(@20) - storage_dead(ptr@16) - storage_dead(data@6) - @0 := Result::Ok { 0: move (@5) } - storage_dead(@5) - return } // Full name: alloc::alloc::{Global}::grow_impl @@ -2556,6 +2200,8 @@ unsafe fn grow_impl<'_0>(@1: &'_0 (Global), @2: NonNull, @3: Layout, @4: Lay old_size@6 := copy ((old_layout@3).size) switch copy (old_size@6) { 0 : usize => { + @0 := alloc_impl<'_>(move (self@1), move (new_layout@4), move (zeroed@5)) + return }, _ => { storage_live(@7) @@ -2568,323 +2214,240 @@ unsafe fn grow_impl<'_0>(@1: &'_0 (Global), @2: NonNull, @3: Layout, @4: Lay storage_dead(@34) @7 := copy (@8) == move (@9) if move (@7) { - } - else { - storage_dead(@9) - storage_dead(@7) - storage_live(@26) - storage_live(self@27) - self@27 := alloc_impl<'_>(move (self@1), move (new_layout@4), move (zeroed@5)) - storage_live(v@52) - match self@27 { - Result::Ok => { - }, - Result::Err => { - storage_dead(v@52) - storage_dead(self@27) - storage_live(@58) - @58 := AllocError { } - storage_live(@59) - @59 := Result::Err { 0: move (@58) } - @0 := move (@59) - storage_dead(@26) - return - }, - } - v@52 := move ((self@27 as variant Result::Ok).0) - @26 := ControlFlow::Continue { 0: copy (v@52) } - storage_dead(v@52) - storage_dead(self@27) - new_ptr@28 := copy ((@26 as variant ControlFlow::Continue).0) - storage_dead(@26) - storage_live(src@29) - ptr@30 := transmute, *mut u8>(copy (ptr@2)) - src@29 := transmute, *const u8>(copy (ptr@2)) - storage_live(dst@31) - @53 := transmute>, *mut Slice>(copy (new_ptr@28)) - dst@31 := cast<*mut Slice, *mut u8>(copy (@53)) - storage_live(@57) - @57 := ub_checks - if copy (@57) { - storage_live(@55) - @55 := transmute, *const ()>(copy (ptr@2)) - storage_live(@56) - @56 := cast<*mut Slice, *mut ()>(copy (@53)) - @54 := core::ptr::copy_nonoverlapping::precondition_check(move (@55), move (@56), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::SIZE), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::ALIGN), copy (old_size@6)) - storage_dead(@56) - storage_dead(@55) - } - else { - } - copy_nonoverlapping(copy (src@29), copy (dst@31), copy (old_size@6)) - storage_dead(@57) - storage_dead(dst@31) - storage_dead(src@29) - switch copy (old_size@6) { - 0 : usize => { - }, - _ => { - @32 := __rust_dealloc(move (ptr@30), move (old_size@6), move (@8)) - }, - } - @0 := Result::Ok { 0: copy (new_ptr@28) } - return - } - storage_dead(@9) - storage_dead(@7) - new_size@10 := copy ((new_layout@4).size) - storage_live(cond@11) - cond@11 := copy (new_size@10) >= copy (old_size@6) - @36 := ub_checks - if copy (@36) { - } - else { - assert(copy (cond@11) == true) - storage_dead(cond@11) - storage_live(ptr@13) - storage_live(self@14) - self@14 := copy (ptr@2) - ptr@13 := transmute, *mut u8>(copy (ptr@2)) - storage_dead(self@14) - storage_live(new_size@15) - new_size@15 := copy (new_size@10) - raw_ptr@12 := __rust_realloc(move (ptr@13), copy (old_size@6), move (@8), copy (new_size@10)) - storage_dead(new_size@15) - storage_dead(ptr@13) - storage_live(@16) - storage_live(self@17) - storage_live(self@18) - storage_live(ptr@19) - ptr@19 := copy (raw_ptr@12) - @38 := cast<*mut u8, *const u8>(copy (raw_ptr@12)) - storage_live(@39) - @39 := transmute<*mut u8, usize>(copy (raw_ptr@12)) - switch move (@39) { - 0 : usize => { - }, - _ => { - storage_dead(@39) - storage_live(@37) + loop { + loop { + storage_dead(@9) + storage_dead(@7) + new_size@10 := copy ((new_layout@4).size) + storage_live(cond@11) + cond@11 := copy (new_size@10) >= copy (old_size@6) + @36 := ub_checks if copy (@36) { - storage_live(@41) - @41 := cast<*mut u8, *mut ()>(copy (raw_ptr@12)) - @40 := core::ptr::non_null::{NonNull}::new_unchecked::precondition_check(move (@41)) - storage_dead(@41) + @35 := core::hint::assert_unchecked::precondition_check(copy (cond@11)) + assert(copy (cond@11) == true) + storage_dead(cond@11) + storage_live(ptr@13) + storage_live(self@14) + self@14 := copy (ptr@2) + ptr@13 := transmute, *mut u8>(copy (ptr@2)) + storage_dead(self@14) + storage_live(new_size@15) + new_size@15 := copy (new_size@10) + raw_ptr@12 := __rust_realloc(move (ptr@13), copy (old_size@6), move (@8), copy (new_size@10)) + storage_dead(new_size@15) + storage_dead(ptr@13) + storage_live(@16) + storage_live(self@17) + storage_live(self@18) + storage_live(ptr@19) + ptr@19 := copy (raw_ptr@12) + @38 := cast<*mut u8, *const u8>(copy (raw_ptr@12)) + storage_live(@39) + @39 := transmute<*mut u8, usize>(copy (raw_ptr@12)) + switch move (@39) { + 0 : usize => { + }, + _ => { + storage_dead(@39) + storage_live(@37) + break 0 + }, + } } else { + assert(copy (cond@11) == true) + storage_dead(cond@11) + storage_live(ptr@13) + storage_live(self@14) + self@14 := copy (ptr@2) + ptr@13 := transmute, *mut u8>(copy (ptr@2)) + storage_dead(self@14) + storage_live(new_size@15) + new_size@15 := copy (new_size@10) + raw_ptr@12 := __rust_realloc(move (ptr@13), copy (old_size@6), move (@8), copy (new_size@10)) + storage_dead(new_size@15) + storage_dead(ptr@13) + storage_live(@16) + storage_live(self@17) + storage_live(self@18) + storage_live(ptr@19) + ptr@19 := copy (raw_ptr@12) + @38 := cast<*mut u8, *const u8>(copy (raw_ptr@12)) + storage_live(@39) + @39 := transmute<*mut u8, usize>(copy (raw_ptr@12)) + switch move (@39) { + 0 : usize => { + }, + _ => { + storage_dead(@39) + storage_live(@37) + if copy (@36) { + break 0 + } + else { + break 1 + } + }, + } } - @37 := NonNull { pointer: copy (@38) } - self@18 := Option::Some { 0: move (@37) } - storage_dead(@37) + storage_dead(@39) + storage_live(@60) + @60 := Option::None { } + self@18 := move (@60) storage_dead(ptr@19) storage_live(v@42) - v@42 := move ((self@18 as variant Option::Some).0) - self@17 := Result::Ok { 0: copy (v@42) } + storage_live(@61) + @61 := AllocError { } + storage_live(@62) + @62 := Result::Err { 0: move (@61) } + self@17 := move (@62) storage_dead(v@42) storage_dead(self@18) storage_live(v@43) - v@43 := move ((self@17 as variant Result::Ok).0) - @16 := ControlFlow::Continue { 0: copy (v@43) } storage_dead(v@43) storage_dead(self@17) - ptr@20 := copy ((@16 as variant ControlFlow::Continue).0) + storage_live(@63) + @63 := AllocError { } + storage_live(@64) + @64 := Result::Err { 0: move (@63) } + @0 := move (@64) storage_dead(@16) - if copy (zeroed@5) { - storage_live(self@22) - storage_live(self@23) - self@23 := copy (raw_ptr@12) - self@22 := copy (raw_ptr@12) offset copy (old_size@6) - storage_dead(self@23) - storage_live(count@24) - count@24 := copy (new_size@10) wrap.- copy (old_size@6) - if copy (@36) { - storage_live(@45) - @45 := cast<*mut u8, *const ()>(copy (self@22)) - storage_live(@46) - @46 := copy (count@24) == const (0 : usize) - @44 := core::ptr::write_bytes::precondition_check(move (@45), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::ALIGN), move (@46)) - storage_dead(@46) - storage_dead(@45) - } - else { - } - @21 := write_bytes[{built_in impl Sized for u8}](move (self@22), const (0 : u8), move (count@24)) - storage_dead(count@24) - storage_dead(self@22) - } - else { - } - storage_live(@25) - storage_live(ptr@47) - storage_live(data@48) - data@48 := transmute, *mut u8>(copy (ptr@20)) - ptr@47 := @PtrFromPartsMut<'_, Slice>(copy (data@48), copy (new_size@10)) - storage_dead(data@48) - storage_live(@51) - if copy (@36) { - storage_live(@50) - @50 := transmute, *mut ()>(copy (ptr@20)) - @49 := core::ptr::non_null::{NonNull}::new_unchecked::precondition_check(move (@50)) - storage_dead(@50) - } - else { - } - @51 := cast<*mut Slice, *const Slice>(copy (ptr@47)) - @25 := NonNull { pointer: copy (@51) } - storage_dead(@51) - storage_dead(ptr@47) - @0 := Result::Ok { 0: move (@25) } - storage_dead(@25) return - }, + break 0 + } + storage_live(@41) + @41 := cast<*mut u8, *mut ()>(copy (raw_ptr@12)) + @40 := core::ptr::non_null::{NonNull}::new_unchecked::precondition_check(move (@41)) + storage_dead(@41) + break 0 } - storage_dead(@39) - storage_live(@60) - @60 := Option::None { } - self@18 := move (@60) + @37 := NonNull { pointer: copy (@38) } + self@18 := Option::Some { 0: move (@37) } + storage_dead(@37) storage_dead(ptr@19) storage_live(v@42) - storage_live(@61) - @61 := AllocError { } - storage_live(@62) - @62 := Result::Err { 0: move (@61) } - self@17 := move (@62) + v@42 := move ((self@18 as variant Option::Some).0) + self@17 := Result::Ok { 0: copy (v@42) } storage_dead(v@42) storage_dead(self@18) storage_live(v@43) + v@43 := move ((self@17 as variant Result::Ok).0) + @16 := ControlFlow::Continue { 0: copy (v@43) } storage_dead(v@43) storage_dead(self@17) - storage_live(@63) - @63 := AllocError { } - storage_live(@64) - @64 := Result::Err { 0: move (@63) } - @0 := move (@64) + ptr@20 := copy ((@16 as variant ControlFlow::Continue).0) storage_dead(@16) - return - } - @35 := core::hint::assert_unchecked::precondition_check(copy (cond@11)) - assert(copy (cond@11) == true) - storage_dead(cond@11) - storage_live(ptr@13) - storage_live(self@14) - self@14 := copy (ptr@2) - ptr@13 := transmute, *mut u8>(copy (ptr@2)) - storage_dead(self@14) - storage_live(new_size@15) - new_size@15 := copy (new_size@10) - raw_ptr@12 := __rust_realloc(move (ptr@13), copy (old_size@6), move (@8), copy (new_size@10)) - storage_dead(new_size@15) - storage_dead(ptr@13) - storage_live(@16) - storage_live(self@17) - storage_live(self@18) - storage_live(ptr@19) - ptr@19 := copy (raw_ptr@12) - @38 := cast<*mut u8, *const u8>(copy (raw_ptr@12)) - storage_live(@39) - @39 := transmute<*mut u8, usize>(copy (raw_ptr@12)) - switch move (@39) { - 0 : usize => { - storage_dead(@39) - storage_live(@60) - @60 := Option::None { } - self@18 := move (@60) - storage_dead(ptr@19) - storage_live(v@42) - storage_live(@61) - @61 := AllocError { } - storage_live(@62) - @62 := Result::Err { 0: move (@61) } - self@17 := move (@62) - storage_dead(v@42) - storage_dead(self@18) - storage_live(v@43) - storage_dead(v@43) - storage_dead(self@17) - storage_live(@63) - @63 := AllocError { } - storage_live(@64) - @64 := Result::Err { 0: move (@63) } - @0 := move (@64) - storage_dead(@16) - return - }, - _ => { - }, - } - storage_dead(@39) - storage_live(@37) - storage_live(@41) - @41 := cast<*mut u8, *mut ()>(copy (raw_ptr@12)) - @40 := core::ptr::non_null::{NonNull}::new_unchecked::precondition_check(move (@41)) - storage_dead(@41) - @37 := NonNull { pointer: copy (@38) } - self@18 := Option::Some { 0: move (@37) } - storage_dead(@37) - storage_dead(ptr@19) - storage_live(v@42) - v@42 := move ((self@18 as variant Option::Some).0) - self@17 := Result::Ok { 0: copy (v@42) } - storage_dead(v@42) - storage_dead(self@18) - storage_live(v@43) - v@43 := move ((self@17 as variant Result::Ok).0) - @16 := ControlFlow::Continue { 0: copy (v@43) } - storage_dead(v@43) - storage_dead(self@17) - ptr@20 := copy ((@16 as variant ControlFlow::Continue).0) - storage_dead(@16) - if copy (zeroed@5) { - storage_live(self@22) - storage_live(self@23) - self@23 := copy (raw_ptr@12) - self@22 := copy (raw_ptr@12) offset copy (old_size@6) - storage_dead(self@23) - storage_live(count@24) - count@24 := copy (new_size@10) wrap.- copy (old_size@6) + if copy (zeroed@5) { + storage_live(self@22) + storage_live(self@23) + self@23 := copy (raw_ptr@12) + self@22 := copy (raw_ptr@12) offset copy (old_size@6) + storage_dead(self@23) + storage_live(count@24) + count@24 := copy (new_size@10) wrap.- copy (old_size@6) + if copy (@36) { + storage_live(@45) + @45 := cast<*mut u8, *const ()>(copy (self@22)) + storage_live(@46) + @46 := copy (count@24) == const (0 : usize) + @44 := core::ptr::write_bytes::precondition_check(move (@45), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::ALIGN), move (@46)) + storage_dead(@46) + storage_dead(@45) + } + else { + } + @21 := write_bytes[{built_in impl Sized for u8}](move (self@22), const (0 : u8), move (count@24)) + storage_dead(count@24) + storage_dead(self@22) + } + else { + } + storage_live(@25) + storage_live(ptr@47) + storage_live(data@48) + data@48 := transmute, *mut u8>(copy (ptr@20)) + ptr@47 := @PtrFromPartsMut<'_, Slice>(copy (data@48), copy (new_size@10)) + storage_dead(data@48) + storage_live(@51) if copy (@36) { - storage_live(@45) - @45 := cast<*mut u8, *const ()>(copy (self@22)) - storage_live(@46) - @46 := copy (count@24) == const (0 : usize) - @44 := core::ptr::write_bytes::precondition_check(move (@45), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::ALIGN), move (@46)) - storage_dead(@46) - storage_dead(@45) + storage_live(@50) + @50 := transmute, *mut ()>(copy (ptr@20)) + @49 := core::ptr::non_null::{NonNull}::new_unchecked::precondition_check(move (@50)) + storage_dead(@50) } else { } - @21 := write_bytes[{built_in impl Sized for u8}](move (self@22), const (0 : u8), move (count@24)) - storage_dead(count@24) - storage_dead(self@22) - } - else { - } - storage_live(@25) - storage_live(ptr@47) - storage_live(data@48) - data@48 := transmute, *mut u8>(copy (ptr@20)) - ptr@47 := @PtrFromPartsMut<'_, Slice>(copy (data@48), copy (new_size@10)) - storage_dead(data@48) - storage_live(@51) - if copy (@36) { - storage_live(@50) - @50 := transmute, *mut ()>(copy (ptr@20)) - @49 := core::ptr::non_null::{NonNull}::new_unchecked::precondition_check(move (@50)) - storage_dead(@50) + @51 := cast<*mut Slice, *const Slice>(copy (ptr@47)) + @25 := NonNull { pointer: copy (@51) } + storage_dead(@51) + storage_dead(ptr@47) + @0 := Result::Ok { 0: move (@25) } + storage_dead(@25) + return } else { + storage_dead(@9) + storage_dead(@7) + storage_live(@26) + storage_live(self@27) + self@27 := alloc_impl<'_>(move (self@1), move (new_layout@4), move (zeroed@5)) + storage_live(v@52) + match self@27 { + Result::Ok => { + v@52 := move ((self@27 as variant Result::Ok).0) + @26 := ControlFlow::Continue { 0: copy (v@52) } + storage_dead(v@52) + storage_dead(self@27) + new_ptr@28 := copy ((@26 as variant ControlFlow::Continue).0) + storage_dead(@26) + storage_live(src@29) + ptr@30 := transmute, *mut u8>(copy (ptr@2)) + src@29 := transmute, *const u8>(copy (ptr@2)) + storage_live(dst@31) + @53 := transmute>, *mut Slice>(copy (new_ptr@28)) + dst@31 := cast<*mut Slice, *mut u8>(copy (@53)) + storage_live(@57) + @57 := ub_checks + if copy (@57) { + storage_live(@55) + @55 := transmute, *const ()>(copy (ptr@2)) + storage_live(@56) + @56 := cast<*mut Slice, *mut ()>(copy (@53)) + @54 := core::ptr::copy_nonoverlapping::precondition_check(move (@55), move (@56), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::SIZE), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::ALIGN), copy (old_size@6)) + storage_dead(@56) + storage_dead(@55) + } + else { + } + copy_nonoverlapping(copy (src@29), copy (dst@31), copy (old_size@6)) + storage_dead(@57) + storage_dead(dst@31) + storage_dead(src@29) + switch copy (old_size@6) { + 0 : usize => { + }, + _ => { + @32 := __rust_dealloc(move (ptr@30), move (old_size@6), move (@8)) + }, + } + @0 := Result::Ok { 0: copy (new_ptr@28) } + return + }, + Result::Err => { + storage_dead(v@52) + storage_dead(self@27) + storage_live(@58) + @58 := AllocError { } + storage_live(@59) + @59 := Result::Err { 0: move (@58) } + @0 := move (@59) + storage_dead(@26) + return + }, + } } - @51 := cast<*mut Slice, *const Slice>(copy (ptr@47)) - @25 := NonNull { pointer: copy (@51) } - storage_dead(@51) - storage_dead(ptr@47) - @0 := Result::Ok { 0: move (@25) } - storage_dead(@25) - return }, } - @0 := alloc_impl<'_>(move (self@1), move (new_layout@4), move (zeroed@5)) - return } // Full name: alloc::alloc::{impl Allocator for Global}::allocate @@ -2926,6 +2489,7 @@ pub unsafe fn {impl Allocator for Global}::deallocate<'_0>(@1: &'_0 (Global), @2 @4 := copy ((layout@3).size) switch move (@4) { 0 : usize => { + return }, _ => { storage_live(ptr@5) @@ -2941,7 +2505,6 @@ pub unsafe fn {impl Allocator for Global}::deallocate<'_0>(@1: &'_0 (Global), @2 return }, } - return } // Full name: alloc::alloc::{impl Allocator for Global}::grow @@ -3070,293 +2633,299 @@ pub unsafe fn {impl Allocator for Global}::shrink<'_0>(@1: &'_0 (Global), @2: No new_size@5 := copy ((new_layout@4).size) switch copy (new_size@5) { 0 : usize => { - }, - _ => { - storage_live(@9) - @31 := copy (((old_layout@3).align).0) - @10 := @discriminant(@31) - storage_live(@11) - storage_live(@45) - @45 := copy (((new_layout@4).align).0) - @11 := @discriminant(@45) - storage_dead(@45) - @9 := copy (@10) == move (@11) - if move (@9) { - } - else { - storage_dead(@11) - storage_dead(@9) - storage_live(@24) - storage_live(self@25) - self@25 := alloc_impl<'_>(move (self@1), move (new_layout@4), const (false)) - storage_live(v@60) - match self@25 { - Result::Ok => { - }, - Result::Err => { - storage_dead(v@60) - storage_dead(self@25) - storage_live(@67) - @67 := AllocError { } - storage_live(@68) - @68 := Result::Err { 0: move (@67) } - @0 := move (@68) - storage_dead(@24) - return - }, - } - v@60 := move ((self@25 as variant Result::Ok).0) - @24 := ControlFlow::Continue { 0: copy (v@60) } - storage_dead(v@60) - storage_dead(self@25) - new_ptr@26 := copy ((@24 as variant ControlFlow::Continue).0) - storage_dead(@24) - storage_live(src@27) - ptr@28 := transmute, *mut u8>(copy (ptr@2)) - src@27 := transmute, *const u8>(copy (ptr@2)) - storage_live(dst@29) - @61 := transmute>, *mut Slice>(copy (new_ptr@26)) - dst@29 := cast<*mut Slice, *mut u8>(copy (@61)) - storage_live(@65) - @65 := ub_checks - if copy (@65) { - storage_live(@63) - @63 := transmute, *const ()>(copy (ptr@2)) - storage_live(@64) - @64 := cast<*mut Slice, *mut ()>(copy (@61)) - @62 := core::ptr::copy_nonoverlapping::precondition_check(move (@63), move (@64), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::SIZE), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::ALIGN), copy (new_size@5)) - storage_dead(@64) - storage_dead(@63) - } - else { - } - copy_nonoverlapping(copy (src@27), copy (dst@29), copy (new_size@5)) - storage_dead(@65) - storage_dead(dst@29) - storage_dead(src@27) - storage_live(@66) - @66 := copy ((old_layout@3).size) - switch move (@66) { - 0 : usize => { - }, - _ => { - @30 := __rust_dealloc(move (ptr@28), move (@66), move (@10)) - }, - } - storage_dead(@66) - @0 := Result::Ok { 0: copy (new_ptr@26) } - return + storage_live(@32) + @32 := copy ((old_layout@3).size) + switch move (@32) { + 0 : usize => { + }, + _ => { + storage_live(ptr@33) + ptr@33 := transmute, *mut u8>(copy (ptr@2)) + storage_live(@34) + storage_live(@35) + @35 := copy (((old_layout@3).align).0) + @34 := @discriminant(@35) + storage_dead(@35) + @6 := __rust_dealloc(move (ptr@33), move (@32), move (@34)) + storage_dead(@34) + storage_dead(ptr@33) + }, } - storage_dead(@11) - storage_dead(@9) - storage_live(cond@12) - @13 := copy ((old_layout@3).size) - cond@12 := copy (new_size@5) <= copy (@13) - @47 := ub_checks - if copy (@47) { - @46 := core::hint::assert_unchecked::precondition_check(copy (cond@12)) - assert(copy (cond@12) == true) - storage_dead(cond@12) - storage_live(ptr@15) - storage_live(self@16) - self@16 := copy (ptr@2) - ptr@15 := transmute, *mut u8>(copy (ptr@2)) - storage_dead(self@16) - storage_live(new_size@17) - new_size@17 := copy (new_size@5) - raw_ptr@14 := __rust_realloc(move (ptr@15), move (@13), move (@10), copy (new_size@5)) - storage_dead(new_size@17) - storage_dead(ptr@15) - storage_live(@18) - storage_live(self@19) - storage_live(self@20) - storage_live(ptr@21) - ptr@21 := copy (raw_ptr@14) - @49 := cast<*mut u8, *const u8>(copy (raw_ptr@14)) - storage_live(@50) - @50 := transmute<*mut u8, usize>(copy (raw_ptr@14)) - switch move (@50) { - 0 : usize => { - storage_dead(@50) - storage_live(@69) - @69 := Option::None { } - self@20 := move (@69) - }, - _ => { - storage_dead(@50) - storage_live(@48) - storage_live(@52) - @52 := cast<*mut u8, *mut ()>(copy (raw_ptr@14)) - @51 := core::ptr::non_null::{NonNull}::new_unchecked::precondition_check(move (@52)) - storage_dead(@52) - @48 := NonNull { pointer: copy (@49) } - self@20 := Option::Some { 0: move (@48) } - storage_dead(@48) - }, - } + storage_dead(@32) + storage_live(@7) + storage_live(data@8) + storage_live(@37) + @37 := copy ((new_layout@4).align) + @36 := transmute[{built_in impl Sized for usize}, {impl ZeroablePrimitive for usize}]>(copy (@37)) + storage_dead(@37) + storage_live(@38) + @38 := transmute[{built_in impl Sized for usize}, {impl ZeroablePrimitive for usize}], *const u8>(copy (@36)) + data@8 := NonNull { pointer: copy (@38) } + storage_dead(@38) + storage_live(ptr@39) + storage_live(data@40) + data@40 := transmute[{built_in impl Sized for usize}, {impl ZeroablePrimitive for usize}], *mut u8>(copy (@36)) + ptr@39 := @PtrFromPartsMut<'_, Slice>(copy (data@40), const (0 : usize)) + storage_dead(data@40) + storage_live(@43) + storage_live(@44) + @44 := ub_checks + if copy (@44) { + storage_live(@42) + @42 := transmute[{built_in impl Sized for usize}, {impl ZeroablePrimitive for usize}], *mut ()>(copy (@36)) + @41 := core::ptr::non_null::{NonNull}::new_unchecked::precondition_check(move (@42)) + storage_dead(@42) } else { - assert(copy (cond@12) == true) - storage_dead(cond@12) - storage_live(ptr@15) - storage_live(self@16) - self@16 := copy (ptr@2) - ptr@15 := transmute, *mut u8>(copy (ptr@2)) - storage_dead(self@16) - storage_live(new_size@17) - new_size@17 := copy (new_size@5) - raw_ptr@14 := __rust_realloc(move (ptr@15), move (@13), move (@10), copy (new_size@5)) - storage_dead(new_size@17) - storage_dead(ptr@15) - storage_live(@18) - storage_live(self@19) - storage_live(self@20) - storage_live(ptr@21) - ptr@21 := copy (raw_ptr@14) - @49 := cast<*mut u8, *const u8>(copy (raw_ptr@14)) - storage_live(@50) - @50 := transmute<*mut u8, usize>(copy (raw_ptr@14)) - switch move (@50) { - 0 : usize => { - storage_dead(@50) - storage_live(@69) - @69 := Option::None { } - self@20 := move (@69) - }, - _ => { - storage_dead(@50) - storage_live(@48) - if copy (@47) { + } + @43 := cast<*mut Slice, *const Slice>(copy (ptr@39)) + @7 := NonNull { pointer: copy (@43) } + storage_dead(@44) + storage_dead(@43) + storage_dead(ptr@39) + storage_dead(data@8) + @0 := Result::Ok { 0: move (@7) } + storage_dead(@7) + return + }, + _ => { + loop { + storage_live(@9) + @31 := copy (((old_layout@3).align).0) + @10 := @discriminant(@31) + storage_live(@11) + storage_live(@45) + @45 := copy (((new_layout@4).align).0) + @11 := @discriminant(@45) + storage_dead(@45) + @9 := copy (@10) == move (@11) + if move (@9) { + loop { + loop { + loop { + storage_dead(@11) + storage_dead(@9) + storage_live(cond@12) + @13 := copy ((old_layout@3).size) + cond@12 := copy (new_size@5) <= copy (@13) + @47 := ub_checks + if copy (@47) { + @46 := core::hint::assert_unchecked::precondition_check(copy (cond@12)) + assert(copy (cond@12) == true) + storage_dead(cond@12) + storage_live(ptr@15) + storage_live(self@16) + self@16 := copy (ptr@2) + ptr@15 := transmute, *mut u8>(copy (ptr@2)) + storage_dead(self@16) + storage_live(new_size@17) + new_size@17 := copy (new_size@5) + raw_ptr@14 := __rust_realloc(move (ptr@15), move (@13), move (@10), copy (new_size@5)) + storage_dead(new_size@17) + storage_dead(ptr@15) + storage_live(@18) + storage_live(self@19) + storage_live(self@20) + storage_live(ptr@21) + ptr@21 := copy (raw_ptr@14) + @49 := cast<*mut u8, *const u8>(copy (raw_ptr@14)) + storage_live(@50) + @50 := transmute<*mut u8, usize>(copy (raw_ptr@14)) + switch move (@50) { + 0 : usize => { + }, + _ => { + storage_dead(@50) + storage_live(@48) + break 0 + }, + } + } + else { + assert(copy (cond@12) == true) + storage_dead(cond@12) + storage_live(ptr@15) + storage_live(self@16) + self@16 := copy (ptr@2) + ptr@15 := transmute, *mut u8>(copy (ptr@2)) + storage_dead(self@16) + storage_live(new_size@17) + new_size@17 := copy (new_size@5) + raw_ptr@14 := __rust_realloc(move (ptr@15), move (@13), move (@10), copy (new_size@5)) + storage_dead(new_size@17) + storage_dead(ptr@15) + storage_live(@18) + storage_live(self@19) + storage_live(self@20) + storage_live(ptr@21) + ptr@21 := copy (raw_ptr@14) + @49 := cast<*mut u8, *const u8>(copy (raw_ptr@14)) + storage_live(@50) + @50 := transmute<*mut u8, usize>(copy (raw_ptr@14)) + switch move (@50) { + 0 : usize => { + }, + _ => { + storage_dead(@50) + storage_live(@48) + if copy (@47) { + break 0 + } + else { + break 1 + } + }, + } + } + storage_dead(@50) + storage_live(@69) + @69 := Option::None { } + self@20 := move (@69) + break 2 + break 0 + } storage_live(@52) @52 := cast<*mut u8, *mut ()>(copy (raw_ptr@14)) @51 := core::ptr::non_null::{NonNull}::new_unchecked::precondition_check(move (@52)) storage_dead(@52) - } - else { + break 0 } @48 := NonNull { pointer: copy (@49) } self@20 := Option::Some { 0: move (@48) } storage_dead(@48) - }, + break 0 + } + storage_dead(ptr@21) + storage_live(v@53) + match self@20 { + Option::None => { + storage_live(@70) + @70 := AllocError { } + storage_live(@71) + @71 := Result::Err { 0: move (@70) } + self@19 := move (@71) + }, + Option::Some => { + v@53 := move ((self@20 as variant Option::Some).0) + self@19 := Result::Ok { 0: copy (v@53) } + }, + } + storage_dead(v@53) + storage_dead(self@20) + storage_live(v@54) + match self@19 { + Result::Ok => { + v@54 := move ((self@19 as variant Result::Ok).0) + @18 := ControlFlow::Continue { 0: copy (v@54) } + storage_dead(v@54) + storage_dead(self@19) + ptr@22 := copy ((@18 as variant ControlFlow::Continue).0) + storage_dead(@18) + storage_live(@23) + storage_live(ptr@55) + storage_live(data@56) + data@56 := transmute, *mut u8>(copy (ptr@22)) + ptr@55 := @PtrFromPartsMut<'_, Slice>(copy (data@56), copy (new_size@5)) + storage_dead(data@56) + storage_live(@59) + if copy (@47) { + storage_live(@58) + @58 := transmute, *mut ()>(copy (ptr@22)) + @57 := core::ptr::non_null::{NonNull}::new_unchecked::precondition_check(move (@58)) + storage_dead(@58) + } + else { + } + @59 := cast<*mut Slice, *const Slice>(copy (ptr@55)) + @23 := NonNull { pointer: copy (@59) } + storage_dead(@59) + storage_dead(ptr@55) + @0 := Result::Ok { 0: move (@23) } + storage_dead(@23) + return + }, + Result::Err => { + storage_dead(v@54) + storage_dead(self@19) + storage_live(@72) + @72 := AllocError { } + storage_live(@73) + @73 := Result::Err { 0: move (@72) } + @0 := move (@73) + storage_dead(@18) + return + }, + } } + else { + storage_dead(@11) + storage_dead(@9) + storage_live(@24) + storage_live(self@25) + self@25 := alloc_impl<'_>(move (self@1), move (new_layout@4), const (false)) + storage_live(v@60) + match self@25 { + Result::Ok => { + v@60 := move ((self@25 as variant Result::Ok).0) + @24 := ControlFlow::Continue { 0: copy (v@60) } + storage_dead(v@60) + storage_dead(self@25) + new_ptr@26 := copy ((@24 as variant ControlFlow::Continue).0) + storage_dead(@24) + storage_live(src@27) + ptr@28 := transmute, *mut u8>(copy (ptr@2)) + src@27 := transmute, *const u8>(copy (ptr@2)) + storage_live(dst@29) + @61 := transmute>, *mut Slice>(copy (new_ptr@26)) + dst@29 := cast<*mut Slice, *mut u8>(copy (@61)) + storage_live(@65) + @65 := ub_checks + if copy (@65) { + storage_live(@63) + @63 := transmute, *const ()>(copy (ptr@2)) + storage_live(@64) + @64 := cast<*mut Slice, *mut ()>(copy (@61)) + @62 := core::ptr::copy_nonoverlapping::precondition_check(move (@63), move (@64), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::SIZE), const ({impl SizedTypeProperties for T}[{built_in impl Sized for u8}]::ALIGN), copy (new_size@5)) + storage_dead(@64) + storage_dead(@63) + } + else { + } + copy_nonoverlapping(copy (src@27), copy (dst@29), copy (new_size@5)) + storage_dead(@65) + storage_dead(dst@29) + storage_dead(src@27) + storage_live(@66) + @66 := copy ((old_layout@3).size) + switch move (@66) { + 0 : usize => { + }, + _ => { + @30 := __rust_dealloc(move (ptr@28), move (@66), move (@10)) + }, + } + storage_dead(@66) + @0 := Result::Ok { 0: copy (new_ptr@26) } + return + }, + Result::Err => { + storage_dead(v@60) + storage_dead(self@25) + storage_live(@67) + @67 := AllocError { } + storage_live(@68) + @68 := Result::Err { 0: move (@67) } + @0 := move (@68) + storage_dead(@24) + return + }, + } + } + break 0 } - storage_dead(ptr@21) - storage_live(v@53) - match self@20 { - Option::None => { - storage_live(@70) - @70 := AllocError { } - storage_live(@71) - @71 := Result::Err { 0: move (@70) } - self@19 := move (@71) - }, - Option::Some => { - v@53 := move ((self@20 as variant Option::Some).0) - self@19 := Result::Ok { 0: copy (v@53) } - }, - } - storage_dead(v@53) - storage_dead(self@20) - storage_live(v@54) - match self@19 { - Result::Ok => { - }, - Result::Err => { - storage_dead(v@54) - storage_dead(self@19) - storage_live(@72) - @72 := AllocError { } - storage_live(@73) - @73 := Result::Err { 0: move (@72) } - @0 := move (@73) - storage_dead(@18) - return - }, - } - v@54 := move ((self@19 as variant Result::Ok).0) - @18 := ControlFlow::Continue { 0: copy (v@54) } - storage_dead(v@54) - storage_dead(self@19) - ptr@22 := copy ((@18 as variant ControlFlow::Continue).0) - storage_dead(@18) - storage_live(@23) - storage_live(ptr@55) - storage_live(data@56) - data@56 := transmute, *mut u8>(copy (ptr@22)) - ptr@55 := @PtrFromPartsMut<'_, Slice>(copy (data@56), copy (new_size@5)) - storage_dead(data@56) - storage_live(@59) - if copy (@47) { - storage_live(@58) - @58 := transmute, *mut ()>(copy (ptr@22)) - @57 := core::ptr::non_null::{NonNull}::new_unchecked::precondition_check(move (@58)) - storage_dead(@58) - } - else { - } - @59 := cast<*mut Slice, *const Slice>(copy (ptr@55)) - @23 := NonNull { pointer: copy (@59) } - storage_dead(@59) - storage_dead(ptr@55) - @0 := Result::Ok { 0: move (@23) } - storage_dead(@23) - return - }, - } - storage_live(@32) - @32 := copy ((old_layout@3).size) - switch move (@32) { - 0 : usize => { + undefined_behavior }, - _ => { - storage_live(ptr@33) - ptr@33 := transmute, *mut u8>(copy (ptr@2)) - storage_live(@34) - storage_live(@35) - @35 := copy (((old_layout@3).align).0) - @34 := @discriminant(@35) - storage_dead(@35) - @6 := __rust_dealloc(move (ptr@33), move (@32), move (@34)) - storage_dead(@34) - storage_dead(ptr@33) - }, - } - storage_dead(@32) - storage_live(@7) - storage_live(data@8) - storage_live(@37) - @37 := copy ((new_layout@4).align) - @36 := transmute[{built_in impl Sized for usize}, {impl ZeroablePrimitive for usize}]>(copy (@37)) - storage_dead(@37) - storage_live(@38) - @38 := transmute[{built_in impl Sized for usize}, {impl ZeroablePrimitive for usize}], *const u8>(copy (@36)) - data@8 := NonNull { pointer: copy (@38) } - storage_dead(@38) - storage_live(ptr@39) - storage_live(data@40) - data@40 := transmute[{built_in impl Sized for usize}, {impl ZeroablePrimitive for usize}], *mut u8>(copy (@36)) - ptr@39 := @PtrFromPartsMut<'_, Slice>(copy (data@40), const (0 : usize)) - storage_dead(data@40) - storage_live(@43) - storage_live(@44) - @44 := ub_checks - if copy (@44) { - storage_live(@42) - @42 := transmute[{built_in impl Sized for usize}, {impl ZeroablePrimitive for usize}], *mut ()>(copy (@36)) - @41 := core::ptr::non_null::{NonNull}::new_unchecked::precondition_check(move (@42)) - storage_dead(@42) } - else { - } - @43 := cast<*mut Slice, *const Slice>(copy (ptr@39)) - @7 := NonNull { pointer: copy (@43) } - storage_dead(@44) - storage_dead(@43) - storage_dead(ptr@39) - storage_dead(data@8) - @0 := Result::Ok { 0: move (@7) } - storage_dead(@7) - return } // Full name: alloc::alloc::{impl Allocator for Global}::by_ref @@ -3470,18 +3039,18 @@ unsafe fn exchange_malloc(@1: usize, @2: usize) -> *mut u8 @4 := alloc_impl<'_>(move (@11), copy (layout@3), const (false)) match @4 { Result::Ok => { + ptr@5 := copy ((@4 as variant Result::Ok).0) + storage_live(@10) + @10 := transmute>, *mut Slice>(copy (ptr@5)) + @0 := cast<*mut Slice, *mut u8>(copy (@10)) + storage_dead(@10) + storage_dead(@4) + return }, Result::Err => { @6 := handle_alloc_error(move (layout@3)) }, } - ptr@5 := copy ((@4 as variant Result::Ok).0) - storage_live(@10) - @10 := transmute>, *mut Slice>(copy (ptr@5)) - @0 := cast<*mut Slice, *mut u8>(copy (@10)) - storage_dead(@10) - storage_dead(@4) - return } // Full name: alloc::boxed::Box diff --git a/charon/tests/ui/reconstruct_early_return.out b/charon/tests/ui/reconstruct_early_return.out index 2776e330d..4e54120ad 100644 --- a/charon/tests/ui/reconstruct_early_return.out +++ b/charon/tests/ui/reconstruct_early_return.out @@ -73,18 +73,16 @@ fn f() -> usize @10 := copy (i@1) panic.+ const (1 : i32) i@1 := move (@10) storage_dead(@3) - continue 0 } else { - break 0 + storage_dead(@4) + storage_dead(@3) + @0 := const (0 : usize) + storage_dead(j@2) + storage_dead(i@1) + return } } - storage_dead(@4) - storage_dead(@3) - @0 := const (0 : usize) - storage_dead(j@2) - storage_dead(i@1) - return } diff --git a/charon/tests/ui/result-unwrap.out b/charon/tests/ui/result-unwrap.out index f770e9ea6..403a8ae38 100644 --- a/charon/tests/ui/result-unwrap.out +++ b/charon/tests/ui/result-unwrap.out @@ -156,6 +156,23 @@ pub fn {impl Debug for u32}::fmt<'_0, '_1, '_2>(@1: &'_0 (u32), @2: &'_1 mut (Fo storage_dead(@4) switch move (@3) { 0 : u32 => { + storage_dead(@3) + storage_live(@5) + storage_live(@6) + @6 := copy (((*(f@2)).0).flags) + @5 := move (@6) & copy (DEBUG_UPPER_HEX_FLAG) + storage_dead(@6) + switch move (@5) { + 0 : u32 => { + storage_dead(@5) + @0 := {impl Display for u32}::fmt<'_, '_, '_>(move (self@1), move (f@2)) + }, + _ => { + storage_dead(@5) + @0 := {impl UpperHex for u32}::fmt<'_, '_, '_>(move (self@1), move (f@2)) + }, + } + return }, _ => { storage_dead(@3) @@ -163,23 +180,6 @@ pub fn {impl Debug for u32}::fmt<'_0, '_1, '_2>(@1: &'_0 (u32), @2: &'_1 mut (Fo return }, } - storage_dead(@3) - storage_live(@5) - storage_live(@6) - @6 := copy (((*(f@2)).0).flags) - @5 := move (@6) & copy (DEBUG_UPPER_HEX_FLAG) - storage_dead(@6) - switch move (@5) { - 0 : u32 => { - storage_dead(@5) - @0 := {impl Display for u32}::fmt<'_, '_, '_>(move (self@1), move (f@2)) - }, - _ => { - storage_dead(@5) - @0 := {impl UpperHex for u32}::fmt<'_, '_, '_>(move (self@1), move (f@2)) - }, - } - return } // Full name: core::fmt::num::{impl Debug for u32} @@ -237,6 +237,8 @@ where storage_live(@5) match self@1 { Result::Ok => { + t@0 := move ((self@1 as variant Result::Ok).0) + return }, Result::Err => { storage_live(e@2) @@ -247,8 +249,6 @@ where @3 := unwrap_failed<'_, '_>(const ("called `Result::unwrap()` on an `Err` value"), move (@4)) }, } - t@0 := move ((self@1 as variant Result::Ok).0) - return } fn test_crate::unwrap(@1: Result[{built_in impl Sized for u32}, {built_in impl Sized for u32}]) -> u32 diff --git a/charon/tests/ui/simple/builtin-drop-mono.out b/charon/tests/ui/simple/builtin-drop-mono.out index 0135ccfd7..d708ad085 100644 --- a/charon/tests/ui/simple/builtin-drop-mono.out +++ b/charon/tests/ui/simple/builtin-drop-mono.out @@ -113,7 +113,7 @@ fn {impl Destruct::>}::drop_in_place::(@1: *mut Slice>}::drop_in_place::(@1: *mut Slice}] *(@5) - continue 0 } } - return } // Full name: test_crate::::{impl Destruct::>}:: @@ -220,7 +218,7 @@ fn {impl Destruct::>}::drop_in_place::>}::drop_in_place::}] *(@7) - continue 0 } } - return } // Full name: test_crate::::{impl Destruct::>}:: diff --git a/charon/tests/ui/simple/lending-iterator-gat.out b/charon/tests/ui/simple/lending-iterator-gat.out index 2a9f27f2e..0b2e02e99 100644 --- a/charon/tests/ui/simple/lending-iterator-gat.out +++ b/charon/tests/ui/simple/lending-iterator-gat.out @@ -155,27 +155,27 @@ where match *(self@1) { Option::Some => { + storage_live(item@2) + item@2 := &mut (*(self@1) as variant Option::Some).0 + storage_live(item@3) + item@3 := &*(*(item@2)) + storage_live(@4) + @4 := Option::None { } + *(self@1) := move (@4) + storage_dead(@4) + storage_live(@5) + @5 := &*(item@3) + @0 := Option::Some { 0: move (@5) } + storage_dead(@5) + storage_dead(item@3) + storage_dead(item@2) + return }, _ => { @0 := Option::None { } return }, } - storage_live(item@2) - item@2 := &mut (*(self@1) as variant Option::Some).0 - storage_live(item@3) - item@3 := &*(*(item@2)) - storage_live(@4) - @4 := Option::None { } - *(self@1) := move (@4) - storage_dead(@4) - storage_live(@5) - @5 := &*(item@3) - @0 := Option::Some { 0: move (@5) } - storage_dead(@5) - storage_dead(item@3) - storage_dead(item@2) - return } // Full name: test_crate::{impl LendingIterator for Option<&'a (T)>[{built_in impl Sized for &'_ (T)}]} @@ -219,36 +219,34 @@ where storage_dead(@5) match @4 { Option::Some => { + storage_live(item@6) + item@6 := move ((@4 as variant Option::Some).0) + storage_live(@7) + @7 := &mut f@2 + storage_live(@8) + storage_live(@9) + @9 := move (item@6) + @8 := (move (@9)) + @3 := @TraitClause3::call_mut<'_>(move (@7), move (@8)) + drop[{built_in impl Destruct for @TraitClause2::Item}] @9 + storage_dead(@9) + storage_dead(@8) + storage_dead(@7) + drop[{built_in impl Destruct for @TraitClause2::Item}] item@6 + storage_dead(item@6) + drop[{impl Destruct for Option[@TraitClause0]}<@TraitClause2::Item>[(@TraitClause2::Item::[@TraitClause0])]] @4 + storage_dead(@4) }, _ => { - break 0 + @0 := () + drop[{impl Destruct for Option[@TraitClause0]}<@TraitClause2::Item>[(@TraitClause2::Item::[@TraitClause0])]] @4 + storage_dead(@4) + drop[{built_in impl Destruct for impl for<'a> FnMut(I::Item<'a>)}] f@2 + drop[{built_in impl Destruct for I}] iter@1 + return }, } - storage_live(item@6) - item@6 := move ((@4 as variant Option::Some).0) - storage_live(@7) - @7 := &mut f@2 - storage_live(@8) - storage_live(@9) - @9 := move (item@6) - @8 := (move (@9)) - @3 := @TraitClause3::call_mut<'_>(move (@7), move (@8)) - drop[{built_in impl Destruct for @TraitClause2::Item}] @9 - storage_dead(@9) - storage_dead(@8) - storage_dead(@7) - drop[{built_in impl Destruct for @TraitClause2::Item}] item@6 - storage_dead(item@6) - drop[{impl Destruct for Option[@TraitClause0]}<@TraitClause2::Item>[(@TraitClause2::Item::[@TraitClause0])]] @4 - storage_dead(@4) - continue 0 } - @0 := () - drop[{impl Destruct for Option[@TraitClause0]}<@TraitClause2::Item>[(@TraitClause2::Item::[@TraitClause0])]] @4 - storage_dead(@4) - drop[{built_in impl Destruct for impl for<'a> FnMut(I::Item<'a>)}] f@2 - drop[{built_in impl Destruct for I}] iter@1 - return } // Full name: test_crate::main::closure @@ -413,6 +411,17 @@ pub fn main() @16 := copy (*(right_val@13)) @14 := move (@15) == move (@16) if move (@14) { + storage_dead(@16) + storage_dead(@15) + storage_dead(@14) + storage_dead(right_val@13) + storage_dead(left_val@12) + storage_dead(@9) + @0 := () + storage_dead(sum@4) + storage_dead(iter@2) + storage_dead(x@1) + return } else { storage_dead(@16) @@ -433,17 +442,6 @@ pub fn main() @23 := Option::None { } panic(core::panicking::assert_failed) } - storage_dead(@16) - storage_dead(@15) - storage_dead(@14) - storage_dead(right_val@13) - storage_dead(left_val@12) - storage_dead(@9) - @0 := () - storage_dead(sum@4) - storage_dead(iter@2) - storage_dead(x@1) - return } diff --git a/charon/tests/ui/simple/mem-discriminant-from-derive.out b/charon/tests/ui/simple/mem-discriminant-from-derive.out index aff9a0261..a42e01da7 100644 --- a/charon/tests/ui/simple/mem-discriminant-from-derive.out +++ b/charon/tests/ui/simple/mem-discriminant-from-derive.out @@ -266,42 +266,45 @@ pub fn {impl PartialEq for Enum}::eq<'_0, '_1>(@1: &'_0 (Enum), @2: &'_1 ( @9 := copy (__arg1_discr@5) @7 := move (@8) == move (@9) if move (@7) { - storage_dead(@9) - storage_dead(@8) - storage_live(@10) - storage_live(@11) - @11 := copy (self@1) - storage_live(@12) - @12 := copy (other@2) - @10 := (move (@11), move (@12)) - storage_dead(@12) - storage_dead(@11) - match *((@10).0) { - Enum::Some => { - match *((@10).1) { - Enum::Some => { - storage_live(__self_0@13) - __self_0@13 := &(*((@10).0) as variant Enum::Some).0 - storage_live(__arg1_0@14) - __arg1_0@14 := &(*((@10).1) as variant Enum::Some).0 - storage_live(@15) - @15 := &__self_0@13 - storage_live(@16) - @16 := &__arg1_0@14 - @0 := {impl PartialEq<&'_0 (B)> for &'_1 (A)}::eq<'_, '_, '_, '_, u8, u8>[{impl PartialEq for u8}](move (@15), move (@16)) - storage_dead(@16) - storage_dead(@15) - storage_dead(__arg1_0@14) - storage_dead(__self_0@13) - }, - _ => { - @0 := const (true) - }, - } - }, - _ => { - @0 := const (true) - }, + loop { + storage_dead(@9) + storage_dead(@8) + storage_live(@10) + storage_live(@11) + @11 := copy (self@1) + storage_live(@12) + @12 := copy (other@2) + @10 := (move (@11), move (@12)) + storage_dead(@12) + storage_dead(@11) + match *((@10).0) { + Enum::Some => { + match *((@10).1) { + Enum::Some => { + storage_live(__self_0@13) + __self_0@13 := &(*((@10).0) as variant Enum::Some).0 + storage_live(__arg1_0@14) + __arg1_0@14 := &(*((@10).1) as variant Enum::Some).0 + storage_live(@15) + @15 := &__self_0@13 + storage_live(@16) + @16 := &__arg1_0@14 + @0 := {impl PartialEq<&'_0 (B)> for &'_1 (A)}::eq<'_, '_, '_, '_, u8, u8>[{impl PartialEq for u8}](move (@15), move (@16)) + storage_dead(@16) + storage_dead(@15) + storage_dead(__arg1_0@14) + storage_dead(__self_0@13) + break 0 + }, + _ => { + }, + } + }, + _ => { + }, + } + @0 := const (true) + break 0 } storage_dead(@10) } diff --git a/charon/tests/ui/simple/slice_index_range.out b/charon/tests/ui/simple/slice_index_range.out index 92b2cc6a7..615c252c0 100644 --- a/charon/tests/ui/simple/slice_index_range.out +++ b/charon/tests/ui/simple/slice_index_range.out @@ -324,6 +324,14 @@ fn slice_index_fail(@1: usize, @2: usize, @3: usize) -> ! @6 := copy (len@3) @4 := move (@5) > move (@6) if move (@4) { + storage_dead(@6) + storage_dead(@5) + storage_live(@7) + storage_live(@8) + @8 := copy (start@1) + storage_live(@9) + @9 := copy (len@3) + @7 := core::slice::index::slice_index_fail::do_panic(move (@8), move (@9)) } else { storage_dead(@6) @@ -336,6 +344,14 @@ fn slice_index_fail(@1: usize, @2: usize, @3: usize) -> ! @12 := copy (len@3) @10 := move (@11) > move (@12) if move (@10) { + storage_dead(@12) + storage_dead(@11) + storage_live(@13) + storage_live(@14) + @14 := copy (end@2) + storage_live(@15) + @15 := copy (len@3) + @13 := core::slice::index::slice_index_fail::do_panic#1(move (@14), move (@15)) } else { storage_dead(@12) @@ -348,6 +364,14 @@ fn slice_index_fail(@1: usize, @2: usize, @3: usize) -> ! @18 := copy (end@2) @16 := move (@17) > move (@18) if move (@16) { + storage_dead(@18) + storage_dead(@17) + storage_live(@19) + storage_live(@20) + @20 := copy (start@1) + storage_live(@21) + @21 := copy (end@2) + @19 := core::slice::index::slice_index_fail::do_panic#2(move (@20), move (@21)) } else { storage_dead(@18) @@ -359,32 +383,8 @@ fn slice_index_fail(@1: usize, @2: usize, @3: usize) -> ! @23 := copy (len@3) @0 := core::slice::index::slice_index_fail::do_panic#3(move (@22), move (@23)) } - storage_dead(@18) - storage_dead(@17) - storage_live(@19) - storage_live(@20) - @20 := copy (start@1) - storage_live(@21) - @21 := copy (end@2) - @19 := core::slice::index::slice_index_fail::do_panic#2(move (@20), move (@21)) } - storage_dead(@12) - storage_dead(@11) - storage_live(@13) - storage_live(@14) - @14 := copy (end@2) - storage_live(@15) - @15 := copy (len@3) - @13 := core::slice::index::slice_index_fail::do_panic#1(move (@14), move (@15)) } - storage_dead(@6) - storage_dead(@5) - storage_live(@7) - storage_live(@8) - @8 := copy (start@1) - storage_live(@9) - @9 := copy (len@3) - @7 := core::slice::index::slice_index_fail::do_panic(move (@8), move (@9)) } // Full name: core::slice::index::private_slice_index::{impl Sealed for Range[{built_in impl Sized for usize}]} @@ -447,58 +447,58 @@ where let @15: *const T; // anonymous local let @16: Option<&'_ (Slice)>[{built_in impl Sized for &'_ (Slice)}]; // anonymous local - storage_live(self@4) - storage_live(rhs@5) - storage_live(new_len@6) - storage_live(@9) - storage_live(@3) - self@4 := copy ((self@1).end) - rhs@5 := copy ((self@1).start) - storage_live(@12) - @12 := copy (self@4) < copy (rhs@5) - if move (@12) { - storage_dead(@12) + loop { + storage_live(self@4) + storage_live(rhs@5) + storage_live(new_len@6) + storage_live(@9) + storage_live(@3) + self@4 := copy ((self@1).end) + rhs@5 := copy ((self@1).start) + storage_live(@12) + @12 := copy (self@4) < copy (rhs@5) + if move (@12) { + storage_dead(@12) + } + else { + storage_live(@13) + @13 := copy (self@4) ub.- copy (rhs@5) + @3 := Option::Some { 0: move (@13) } + storage_dead(@13) + storage_dead(@12) + new_len@6 := copy ((@3 as variant Option::Some).0) + storage_live(@7) + storage_live(@8) + @8 := copy (slice@2.metadata) + @7 := copy (self@4) <= move (@8) + if move (@7) { + storage_dead(@8) + storage_live(@10) + storage_live(@11) + @11 := &raw const *(slice@2) with_metadata(copy (slice@2.metadata)) + storage_live(@14) + storage_live(@15) + @14 := cast<*const Slice, *const T>(copy (@11)) + @15 := copy (@14) offset copy (rhs@5) + @10 := @PtrFromPartsShared<'_, Slice>(copy (@15), copy (new_len@6)) + storage_dead(@15) + storage_dead(@14) + storage_dead(@11) + @9 := &*(@10) with_metadata(copy (@10.metadata)) + @0 := Option::Some { 0: copy (@9) } + storage_dead(@10) + storage_dead(@3) + break 0 + } + else { + storage_dead(@8) + } + } storage_dead(@3) storage_live(@16) @16 := Option::None { } @0 := move (@16) - } - else { - storage_live(@13) - @13 := copy (self@4) ub.- copy (rhs@5) - @3 := Option::Some { 0: move (@13) } - storage_dead(@13) - storage_dead(@12) - new_len@6 := copy ((@3 as variant Option::Some).0) - storage_live(@7) - storage_live(@8) - @8 := copy (slice@2.metadata) - @7 := copy (self@4) <= move (@8) - if move (@7) { - storage_dead(@8) - storage_live(@10) - storage_live(@11) - @11 := &raw const *(slice@2) with_metadata(copy (slice@2.metadata)) - storage_live(@14) - storage_live(@15) - @14 := cast<*const Slice, *const T>(copy (@11)) - @15 := copy (@14) offset copy (rhs@5) - @10 := @PtrFromPartsShared<'_, Slice>(copy (@15), copy (new_len@6)) - storage_dead(@15) - storage_dead(@14) - storage_dead(@11) - @9 := &*(@10) with_metadata(copy (@10.metadata)) - @0 := Option::Some { 0: copy (@9) } - storage_dead(@10) - storage_dead(@3) - } - else { - storage_dead(@8) - storage_dead(@3) - storage_live(@16) - @16 := Option::None { } - @0 := move (@16) - } + break 0 } storage_dead(@7) return @@ -527,58 +527,58 @@ where let @15: *mut T; // anonymous local let @16: Option<&'_ mut (Slice)>[{built_in impl Sized for &'_ mut (Slice)}]; // anonymous local - storage_live(self@4) - storage_live(rhs@5) - storage_live(new_len@6) - storage_live(@9) - storage_live(@3) - self@4 := copy ((self@1).end) - rhs@5 := copy ((self@1).start) - storage_live(@12) - @12 := copy (self@4) < copy (rhs@5) - if move (@12) { - storage_dead(@12) + loop { + storage_live(self@4) + storage_live(rhs@5) + storage_live(new_len@6) + storage_live(@9) + storage_live(@3) + self@4 := copy ((self@1).end) + rhs@5 := copy ((self@1).start) + storage_live(@12) + @12 := copy (self@4) < copy (rhs@5) + if move (@12) { + storage_dead(@12) + } + else { + storage_live(@13) + @13 := copy (self@4) ub.- copy (rhs@5) + @3 := Option::Some { 0: move (@13) } + storage_dead(@13) + storage_dead(@12) + new_len@6 := copy ((@3 as variant Option::Some).0) + storage_live(@7) + storage_live(@8) + @8 := copy (slice@2.metadata) + @7 := copy (self@4) <= move (@8) + if move (@7) { + storage_dead(@8) + storage_live(@10) + storage_live(ptr@11) + ptr@11 := &raw mut *(slice@2) with_metadata(copy (slice@2.metadata)) + storage_live(@14) + storage_live(@15) + @14 := cast<*mut Slice, *mut T>(copy (ptr@11)) + @15 := copy (@14) offset copy (rhs@5) + @10 := @PtrFromPartsMut<'_, Slice>(copy (@15), copy (new_len@6)) + storage_dead(@15) + storage_dead(@14) + storage_dead(ptr@11) + @9 := &mut *(@10) with_metadata(copy (@10.metadata)) + @0 := Option::Some { 0: copy (@9) } + storage_dead(@10) + storage_dead(@3) + break 0 + } + else { + storage_dead(@8) + } + } storage_dead(@3) storage_live(@16) @16 := Option::None { } @0 := move (@16) - } - else { - storage_live(@13) - @13 := copy (self@4) ub.- copy (rhs@5) - @3 := Option::Some { 0: move (@13) } - storage_dead(@13) - storage_dead(@12) - new_len@6 := copy ((@3 as variant Option::Some).0) - storage_live(@7) - storage_live(@8) - @8 := copy (slice@2.metadata) - @7 := copy (self@4) <= move (@8) - if move (@7) { - storage_dead(@8) - storage_live(@10) - storage_live(ptr@11) - ptr@11 := &raw mut *(slice@2) with_metadata(copy (slice@2.metadata)) - storage_live(@14) - storage_live(@15) - @14 := cast<*mut Slice, *mut T>(copy (ptr@11)) - @15 := copy (@14) offset copy (rhs@5) - @10 := @PtrFromPartsMut<'_, Slice>(copy (@15), copy (new_len@6)) - storage_dead(@15) - storage_dead(@14) - storage_dead(ptr@11) - @9 := &mut *(@10) with_metadata(copy (@10.metadata)) - @0 := Option::Some { 0: copy (@9) } - storage_dead(@10) - storage_dead(@3) - } - else { - storage_dead(@8) - storage_dead(@3) - storage_live(@16) - @16 := Option::None { } - @0 := move (@16) - } + break 0 } storage_dead(@7) return @@ -1032,50 +1032,49 @@ where } else { } - storage_live(@8) - storage_live(@11) - @11 := copy (exclusive_end@5) < copy (self@15) - if move (@11) { - storage_dead(@11) - storage_live(@18) - @18 := Option::None { } - @0 := move (@18) - storage_dead(@6) - storage_dead(@8) - } - else { - new_len@12 := copy (exclusive_end@5) ub.- copy (self@15) - storage_dead(@11) - storage_live(@6) - storage_live(@7) - @7 := copy (slice@2.metadata) - @6 := copy (exclusive_end@5) <= move (@7) - if move (@6) { - storage_dead(@7) - storage_live(@9) - storage_live(@10) - @10 := &raw const *(slice@2) with_metadata(copy (slice@2.metadata)) - storage_live(@13) - storage_live(@14) - @13 := cast<*const Slice, *const T>(copy (@10)) - @14 := copy (@13) offset copy (self@15) - @9 := @PtrFromPartsShared<'_, Slice>(copy (@14), copy (new_len@12)) - storage_dead(@14) - storage_dead(@13) - storage_dead(@10) - @8 := &*(@9) with_metadata(copy (@9.metadata)) - @0 := Option::Some { 0: copy (@8) } - storage_dead(@9) + loop { + storage_live(@8) + storage_live(@11) + @11 := copy (exclusive_end@5) < copy (self@15) + if move (@11) { + storage_dead(@11) } else { - storage_dead(@7) - storage_live(@18) - @18 := Option::None { } - @0 := move (@18) + new_len@12 := copy (exclusive_end@5) ub.- copy (self@15) + storage_dead(@11) + storage_live(@6) + storage_live(@7) + @7 := copy (slice@2.metadata) + @6 := copy (exclusive_end@5) <= move (@7) + if move (@6) { + storage_dead(@7) + storage_live(@9) + storage_live(@10) + @10 := &raw const *(slice@2) with_metadata(copy (slice@2.metadata)) + storage_live(@13) + storage_live(@14) + @13 := cast<*const Slice, *const T>(copy (@10)) + @14 := copy (@13) offset copy (self@15) + @9 := @PtrFromPartsShared<'_, Slice>(copy (@14), copy (new_len@12)) + storage_dead(@14) + storage_dead(@13) + storage_dead(@10) + @8 := &*(@9) with_metadata(copy (@9.metadata)) + @0 := Option::Some { 0: copy (@8) } + storage_dead(@9) + break 0 + } + else { + storage_dead(@7) + } } - storage_dead(@6) - storage_dead(@8) + storage_live(@18) + @18 := Option::None { } + @0 := move (@18) + break 0 } + storage_dead(@6) + storage_dead(@8) } storage_dead(@3) return @@ -1128,50 +1127,49 @@ where } else { } - storage_live(@8) - storage_live(@11) - @11 := copy (exclusive_end@5) < copy (self@15) - if move (@11) { - storage_dead(@11) - storage_live(@18) - @18 := Option::None { } - @0 := move (@18) - storage_dead(@6) - storage_dead(@8) - } - else { - new_len@12 := copy (exclusive_end@5) ub.- copy (self@15) - storage_dead(@11) - storage_live(@6) - storage_live(@7) - @7 := copy (slice@2.metadata) - @6 := copy (exclusive_end@5) <= move (@7) - if move (@6) { - storage_dead(@7) - storage_live(@9) - storage_live(ptr@10) - ptr@10 := &raw mut *(slice@2) with_metadata(copy (slice@2.metadata)) - storage_live(@13) - storage_live(@14) - @13 := cast<*mut Slice, *mut T>(copy (ptr@10)) - @14 := copy (@13) offset copy (self@15) - @9 := @PtrFromPartsMut<'_, Slice>(copy (@14), copy (new_len@12)) - storage_dead(@14) - storage_dead(@13) - storage_dead(ptr@10) - @8 := &mut *(@9) with_metadata(copy (@9.metadata)) - @0 := Option::Some { 0: copy (@8) } - storage_dead(@9) + loop { + storage_live(@8) + storage_live(@11) + @11 := copy (exclusive_end@5) < copy (self@15) + if move (@11) { + storage_dead(@11) } else { - storage_dead(@7) - storage_live(@18) - @18 := Option::None { } - @0 := move (@18) + new_len@12 := copy (exclusive_end@5) ub.- copy (self@15) + storage_dead(@11) + storage_live(@6) + storage_live(@7) + @7 := copy (slice@2.metadata) + @6 := copy (exclusive_end@5) <= move (@7) + if move (@6) { + storage_dead(@7) + storage_live(@9) + storage_live(ptr@10) + ptr@10 := &raw mut *(slice@2) with_metadata(copy (slice@2.metadata)) + storage_live(@13) + storage_live(@14) + @13 := cast<*mut Slice, *mut T>(copy (ptr@10)) + @14 := copy (@13) offset copy (self@15) + @9 := @PtrFromPartsMut<'_, Slice>(copy (@14), copy (new_len@12)) + storage_dead(@14) + storage_dead(@13) + storage_dead(ptr@10) + @8 := &mut *(@9) with_metadata(copy (@9.metadata)) + @0 := Option::Some { 0: copy (@8) } + storage_dead(@9) + break 0 + } + else { + storage_dead(@7) + } } - storage_dead(@6) - storage_dead(@8) + storage_live(@18) + @18 := Option::None { } + @0 := move (@18) + break 0 } + storage_dead(@6) + storage_dead(@8) } storage_dead(@3) return diff --git a/charon/tests/ui/skip-borrowck.out b/charon/tests/ui/skip-borrowck.out index c8cecf543..2f32767cc 100644 --- a/charon/tests/ui/skip-borrowck.out +++ b/charon/tests/ui/skip-borrowck.out @@ -105,55 +105,55 @@ pub fn choose_test() @10 := copy (*(z@3)) @9 := move (@10) == const (1 : i32) if move (@9) { - } - else { storage_dead(@10) - panic(core::panicking::panic) - } - storage_dead(@10) - storage_dead(@9) - storage_live(@11) - storage_live(@12) - // drop(z) - @12 := copy (x@1) - @11 := move (@12) == const (1 : i32) - if move (@11) { - } - else { - storage_dead(@12) - panic(core::panicking::panic) - } - storage_dead(@12) - storage_dead(@11) - storage_live(@13) - storage_live(@14) - @14 := copy (y@2) - @13 := move (@14) == const (0 : i32) - if move (@13) { + storage_dead(@9) + storage_live(@11) + storage_live(@12) + // drop(z) + @12 := copy (x@1) + @11 := move (@12) == const (1 : i32) + if move (@11) { + storage_dead(@12) + storage_dead(@11) + storage_live(@13) + storage_live(@14) + @14 := copy (y@2) + @13 := move (@14) == const (0 : i32) + if move (@13) { + storage_dead(@14) + storage_dead(@13) + storage_live(@15) + storage_live(@16) + @16 := copy (*(z@3)) + @15 := move (@16) == const (1 : i32) + if move (@15) { + storage_dead(@16) + storage_dead(@15) + @0 := () + storage_dead(z@3) + storage_dead(y@2) + storage_dead(x@1) + return + } + else { + storage_dead(@16) + panic(core::panicking::panic) + } + } + else { + storage_dead(@14) + panic(core::panicking::panic) + } + } + else { + storage_dead(@12) + panic(core::panicking::panic) + } } else { - storage_dead(@14) - panic(core::panicking::panic) - } - storage_dead(@14) - storage_dead(@13) - storage_live(@15) - storage_live(@16) - @16 := copy (*(z@3)) - @15 := move (@16) == const (1 : i32) - if move (@15) { - } - else { - storage_dead(@16) + storage_dead(@10) panic(core::panicking::panic) } - storage_dead(@16) - storage_dead(@15) - @0 := () - storage_dead(z@3) - storage_dead(y@2) - storage_dead(x@1) - return } diff --git a/charon/tests/ui/slice-index-range.out b/charon/tests/ui/slice-index-range.out index e71dd4267..f5e3a9168 100644 --- a/charon/tests/ui/slice-index-range.out +++ b/charon/tests/ui/slice-index-range.out @@ -246,6 +246,14 @@ fn slice_index_fail(@1: usize, @2: usize, @3: usize) -> ! @6 := copy (len@3) @4 := move (@5) > move (@6) if move (@4) { + storage_dead(@6) + storage_dead(@5) + storage_live(@7) + storage_live(@8) + @8 := copy (start@1) + storage_live(@9) + @9 := copy (len@3) + @7 := core::slice::index::slice_index_fail::do_panic(move (@8), move (@9)) } else { storage_dead(@6) @@ -258,6 +266,14 @@ fn slice_index_fail(@1: usize, @2: usize, @3: usize) -> ! @12 := copy (len@3) @10 := move (@11) > move (@12) if move (@10) { + storage_dead(@12) + storage_dead(@11) + storage_live(@13) + storage_live(@14) + @14 := copy (end@2) + storage_live(@15) + @15 := copy (len@3) + @13 := core::slice::index::slice_index_fail::do_panic#1(move (@14), move (@15)) } else { storage_dead(@12) @@ -270,6 +286,14 @@ fn slice_index_fail(@1: usize, @2: usize, @3: usize) -> ! @18 := copy (end@2) @16 := move (@17) > move (@18) if move (@16) { + storage_dead(@18) + storage_dead(@17) + storage_live(@19) + storage_live(@20) + @20 := copy (start@1) + storage_live(@21) + @21 := copy (end@2) + @19 := core::slice::index::slice_index_fail::do_panic#2(move (@20), move (@21)) } else { storage_dead(@18) @@ -281,32 +305,8 @@ fn slice_index_fail(@1: usize, @2: usize, @3: usize) -> ! @23 := copy (len@3) @0 := core::slice::index::slice_index_fail::do_panic#3(move (@22), move (@23)) } - storage_dead(@18) - storage_dead(@17) - storage_live(@19) - storage_live(@20) - @20 := copy (start@1) - storage_live(@21) - @21 := copy (end@2) - @19 := core::slice::index::slice_index_fail::do_panic#2(move (@20), move (@21)) } - storage_dead(@12) - storage_dead(@11) - storage_live(@13) - storage_live(@14) - @14 := copy (end@2) - storage_live(@15) - @15 := copy (len@3) - @13 := core::slice::index::slice_index_fail::do_panic#1(move (@14), move (@15)) } - storage_dead(@6) - storage_dead(@5) - storage_live(@7) - storage_live(@8) - @8 := copy (start@1) - storage_live(@9) - @9 := copy (len@3) - @7 := core::slice::index::slice_index_fail::do_panic(move (@8), move (@9)) } // Full name: core::slice::index::private_slice_index::{impl Sealed for Range[{built_in impl Sized for usize}]} @@ -363,58 +363,58 @@ where let @15: *const T; // anonymous local let @16: Option<&'_ (Slice)>[{built_in impl Sized for &'_ (Slice)}]; // anonymous local - storage_live(self@4) - storage_live(rhs@5) - storage_live(new_len@6) - storage_live(@9) - storage_live(@3) - self@4 := copy ((self@1).end) - rhs@5 := copy ((self@1).start) - storage_live(@12) - @12 := copy (self@4) < copy (rhs@5) - if move (@12) { - storage_dead(@12) + loop { + storage_live(self@4) + storage_live(rhs@5) + storage_live(new_len@6) + storage_live(@9) + storage_live(@3) + self@4 := copy ((self@1).end) + rhs@5 := copy ((self@1).start) + storage_live(@12) + @12 := copy (self@4) < copy (rhs@5) + if move (@12) { + storage_dead(@12) + } + else { + storage_live(@13) + @13 := copy (self@4) ub.- copy (rhs@5) + @3 := Option::Some { 0: move (@13) } + storage_dead(@13) + storage_dead(@12) + new_len@6 := copy ((@3 as variant Option::Some).0) + storage_live(@7) + storage_live(@8) + @8 := copy (slice@2.metadata) + @7 := copy (self@4) <= move (@8) + if move (@7) { + storage_dead(@8) + storage_live(@10) + storage_live(@11) + @11 := &raw const *(slice@2) with_metadata(copy (slice@2.metadata)) + storage_live(@14) + storage_live(@15) + @14 := cast<*const Slice, *const T>(copy (@11)) + @15 := copy (@14) offset copy (rhs@5) + @10 := @PtrFromPartsShared<'_, Slice>(copy (@15), copy (new_len@6)) + storage_dead(@15) + storage_dead(@14) + storage_dead(@11) + @9 := &*(@10) with_metadata(copy (@10.metadata)) + @0 := Option::Some { 0: copy (@9) } + storage_dead(@10) + storage_dead(@3) + break 0 + } + else { + storage_dead(@8) + } + } storage_dead(@3) storage_live(@16) @16 := Option::None { } @0 := move (@16) - } - else { - storage_live(@13) - @13 := copy (self@4) ub.- copy (rhs@5) - @3 := Option::Some { 0: move (@13) } - storage_dead(@13) - storage_dead(@12) - new_len@6 := copy ((@3 as variant Option::Some).0) - storage_live(@7) - storage_live(@8) - @8 := copy (slice@2.metadata) - @7 := copy (self@4) <= move (@8) - if move (@7) { - storage_dead(@8) - storage_live(@10) - storage_live(@11) - @11 := &raw const *(slice@2) with_metadata(copy (slice@2.metadata)) - storage_live(@14) - storage_live(@15) - @14 := cast<*const Slice, *const T>(copy (@11)) - @15 := copy (@14) offset copy (rhs@5) - @10 := @PtrFromPartsShared<'_, Slice>(copy (@15), copy (new_len@6)) - storage_dead(@15) - storage_dead(@14) - storage_dead(@11) - @9 := &*(@10) with_metadata(copy (@10.metadata)) - @0 := Option::Some { 0: copy (@9) } - storage_dead(@10) - storage_dead(@3) - } - else { - storage_dead(@8) - storage_dead(@3) - storage_live(@16) - @16 := Option::None { } - @0 := move (@16) - } + break 0 } storage_dead(@7) return @@ -443,58 +443,58 @@ where let @15: *mut T; // anonymous local let @16: Option<&'_ mut (Slice)>[{built_in impl Sized for &'_ mut (Slice)}]; // anonymous local - storage_live(self@4) - storage_live(rhs@5) - storage_live(new_len@6) - storage_live(@9) - storage_live(@3) - self@4 := copy ((self@1).end) - rhs@5 := copy ((self@1).start) - storage_live(@12) - @12 := copy (self@4) < copy (rhs@5) - if move (@12) { - storage_dead(@12) + loop { + storage_live(self@4) + storage_live(rhs@5) + storage_live(new_len@6) + storage_live(@9) + storage_live(@3) + self@4 := copy ((self@1).end) + rhs@5 := copy ((self@1).start) + storage_live(@12) + @12 := copy (self@4) < copy (rhs@5) + if move (@12) { + storage_dead(@12) + } + else { + storage_live(@13) + @13 := copy (self@4) ub.- copy (rhs@5) + @3 := Option::Some { 0: move (@13) } + storage_dead(@13) + storage_dead(@12) + new_len@6 := copy ((@3 as variant Option::Some).0) + storage_live(@7) + storage_live(@8) + @8 := copy (slice@2.metadata) + @7 := copy (self@4) <= move (@8) + if move (@7) { + storage_dead(@8) + storage_live(@10) + storage_live(ptr@11) + ptr@11 := &raw mut *(slice@2) with_metadata(copy (slice@2.metadata)) + storage_live(@14) + storage_live(@15) + @14 := cast<*mut Slice, *mut T>(copy (ptr@11)) + @15 := copy (@14) offset copy (rhs@5) + @10 := @PtrFromPartsMut<'_, Slice>(copy (@15), copy (new_len@6)) + storage_dead(@15) + storage_dead(@14) + storage_dead(ptr@11) + @9 := &mut *(@10) with_metadata(copy (@10.metadata)) + @0 := Option::Some { 0: copy (@9) } + storage_dead(@10) + storage_dead(@3) + break 0 + } + else { + storage_dead(@8) + } + } storage_dead(@3) storage_live(@16) @16 := Option::None { } @0 := move (@16) - } - else { - storage_live(@13) - @13 := copy (self@4) ub.- copy (rhs@5) - @3 := Option::Some { 0: move (@13) } - storage_dead(@13) - storage_dead(@12) - new_len@6 := copy ((@3 as variant Option::Some).0) - storage_live(@7) - storage_live(@8) - @8 := copy (slice@2.metadata) - @7 := copy (self@4) <= move (@8) - if move (@7) { - storage_dead(@8) - storage_live(@10) - storage_live(ptr@11) - ptr@11 := &raw mut *(slice@2) with_metadata(copy (slice@2.metadata)) - storage_live(@14) - storage_live(@15) - @14 := cast<*mut Slice, *mut T>(copy (ptr@11)) - @15 := copy (@14) offset copy (rhs@5) - @10 := @PtrFromPartsMut<'_, Slice>(copy (@15), copy (new_len@6)) - storage_dead(@15) - storage_dead(@14) - storage_dead(ptr@11) - @9 := &mut *(@10) with_metadata(copy (@10.metadata)) - @0 := Option::Some { 0: copy (@9) } - storage_dead(@10) - storage_dead(@3) - } - else { - storage_dead(@8) - storage_dead(@3) - storage_live(@16) - @16 := Option::None { } - @0 := move (@16) - } + break 0 } storage_dead(@7) return @@ -928,20 +928,20 @@ fn main() @7 := copy (*(@10)) @6 := move (@7) == const (3 : i32) if move (@6) { + storage_dead(@7) + storage_dead(@8) + storage_dead(@6) + @0 := () + storage_dead(@3) + storage_dead(slice@2) + storage_dead(array@1) + return } else { storage_dead(@7) storage_dead(@8) panic(core::panicking::panic) } - storage_dead(@7) - storage_dead(@8) - storage_dead(@6) - @0 := () - storage_dead(@3) - storage_dead(slice@2) - storage_dead(array@1) - return } diff --git a/charon/tests/ui/traits.out b/charon/tests/ui/traits.out index 3fa4635c2..ea2d4a12e 100644 --- a/charon/tests/ui/traits.out +++ b/charon/tests/ui/traits.out @@ -239,14 +239,14 @@ where match *(self@1) { Option::None => { + @0 := const (false) + return }, Option::Some => { @0 := const (true) return }, } - @0 := const (false) - return } // Full name: test_crate::{impl BoolTrait for Option[@TraitClause0]}::ret_true diff --git a/charon/tests/ui/vtables.out b/charon/tests/ui/vtables.out index d6f794f75..9bf6f35a3 100644 --- a/charon/tests/ui/vtables.out +++ b/charon/tests/ui/vtables.out @@ -390,15 +390,15 @@ fn {impl NoParam for i32}::dummy<'_0>(@1: &'_0 (i32)) @3 := copy (*(self@1)) @2 := move (@3) > const (0 : i32) if move (@2) { + storage_dead(@3) + storage_dead(@2) + @0 := () + return } else { storage_dead(@3) panic(core::panicking::panic) } - storage_dead(@3) - storage_dead(@2) - @0 := () - return } // Full name: test_crate::{impl NoParam for i32} @@ -666,17 +666,17 @@ fn {impl BaseOn for i32}::operate_on<'_0, '_1>(@1: &'_0 (i32), @2: &'_1 (i3 @5 := copy (*(t@2)) @3 := move (@4) > move (@5) if move (@3) { + storage_dead(@5) + storage_dead(@4) + storage_dead(@3) + @0 := () + return } else { storage_dead(@5) storage_dead(@4) panic(core::panicking::panic) } - storage_dead(@5) - storage_dead(@4) - storage_dead(@3) - @0 := () - return } // Full name: test_crate::{impl BaseOn for i32}::operate_on::{vtable_method} @@ -742,17 +742,17 @@ fn {impl BaseOn for i32}::operate_on<'_0, '_1>(@1: &'_0 (i32), @2: &'_1 (i6 @6 := copy (*(t@2)) @3 := move (@4) > move (@6) if move (@3) { + storage_dead(@6) + storage_dead(@4) + storage_dead(@3) + @0 := () + return } else { storage_dead(@6) storage_dead(@4) panic(core::panicking::panic) } - storage_dead(@6) - storage_dead(@4) - storage_dead(@3) - @0 := () - return } // Full name: test_crate::{impl BaseOn for i32}::operate_on::{vtable_method} @@ -920,17 +920,17 @@ fn {impl LifetimeTrait for i32}::lifetime_method<'a, '_1>(@1: &'_1 (i32), @2: &' @5 := copy (*(arg@2)) @3 := move (@4) > move (@5) if move (@3) { + storage_dead(@5) + storage_dead(@4) + storage_dead(@3) + @0 := copy (arg@2) + return } else { storage_dead(@5) storage_dead(@4) panic(core::panicking::panic) } - storage_dead(@5) - storage_dead(@4) - storage_dead(@3) - @0 := copy (arg@2) - return } // Full name: test_crate::{impl LifetimeTrait for i32}::lifetime_method::{vtable_method} @@ -1186,283 +1186,283 @@ fn main() @5 := &*(x@1) with_metadata(copy (x@1.metadata)) @4 := (move (*(@5.metadata)).method_check)(move (@5)) if move (@4) { - } - else { storage_dead(@5) - panic(core::panicking::panic) - } - storage_dead(@5) - storage_dead(@4) - storage_live(y@6) - storage_live(@7) - storage_live(@8) - storage_live(@9) - @9 := const (99 : i32) - @8 := &mut @9 - @7 := &mut *(@8) - y@6 := unsize_cast<&'_ mut (i32), &'_ mut ((dyn exists<_dyn> [@TraitClause0_1]: Modifiable<_dyn, i32> + _dyn : '_)), {impl Modifiable for i32}[{built_in impl Sized for i32}, {impl Clone for i32}]>(move (@7)) - storage_dead(@7) - storage_dead(@8) - storage_live(@10) - storage_live(@11) - storage_live(@12) - storage_live(@13) - storage_live(@14) - storage_live(@15) - storage_live(@16) - storage_live(@17) - @17 := const ("Hello") - @16 := &*(@17) with_metadata(copy (@17.metadata)) - @15 := {impl ToString for T}::to_string<'_, Str>[{built_in impl MetaSized for Str}, {impl Display for Str}](move (@16)) - storage_dead(@16) - @14 := &@15 - @13 := &*(@14) - @12 := modify_trait_object<'_, String>[{built_in impl Sized for String}, {impl Clone for String}](move (@13)) - @11 := &@12 - storage_dead(@13) - @10 := is_empty<'_>(move (@11)) - if move (@10) { - } - else { - storage_dead(@11) - drop[{impl Destruct for String}] @12 - drop[{impl Destruct for String}] @15 - storage_dead(@17) - storage_dead(@15) - storage_dead(@14) - storage_dead(@12) - storage_dead(@10) - storage_live(@18) - storage_live(@19) - storage_live(@20) - storage_live(@21) - @21 := &two-phase-mut *(y@6) with_metadata(copy (y@6.metadata)) - storage_live(@22) - storage_live(@23) - storage_live(@24) - @24 := const (100 : i32) - @23 := &mut @24 - @22 := &*(@23) - @20 := (move (*(@21.metadata)).method_modify)(move (@21), move (@22)) - storage_live(@88) - storage_live(@89) - @89 := const (100 : i32) - @88 := &@89 - storage_dead(@22) - storage_dead(@21) - @19 := &@20 - storage_live(@25) - @84 := move (@88) - @25 := &*(@84) - @18 := (move (@19), move (@25)) - storage_dead(@25) - storage_dead(@19) - storage_live(left_val@26) - left_val@26 := copy ((@18).0) - storage_live(right_val@27) - right_val@27 := copy ((@18).1) - storage_live(@28) - storage_live(@29) - @29 := copy (*(left_val@26)) - storage_live(@30) - @30 := copy (*(right_val@27)) - @28 := move (@29) == move (@30) - if move (@28) { - } - else { - storage_dead(@30) - storage_dead(@29) - storage_live(kind@31) - kind@31 := AssertKind::Eq { } - storage_live(@32) - @32 := move (kind@31) - storage_live(@33) - storage_live(@34) - @34 := &*(left_val@26) - @33 := &*(@34) - storage_live(@35) - storage_live(@36) - @36 := &*(right_val@27) - @35 := &*(@36) - storage_live(@37) - @37 := Option::None { } - panic(core::panicking::assert_failed) - } - storage_live(@90) - storage_live(@91) - @91 := const (42 : i32) - @90 := &@91 - storage_dead(@30) - storage_dead(@29) - storage_dead(@28) - storage_dead(right_val@27) - storage_dead(left_val@26) - storage_dead(@24) - storage_dead(@23) - storage_dead(@20) - storage_dead(@18) - storage_live(z@38) - storage_live(@39) - storage_live(@40) - storage_live(@41) - storage_live(@42) - @83 := move (@90) - @42 := &*(@83) - @41 := &*(@42) - @40 := to_dyn_obj<'_, i32>[{built_in impl Sized for i32}, {impl NoParam for i32}](move (@41)) - @39 := &*(@40) with_metadata(copy (@40.metadata)) - z@38 := unsize_cast<&'_ ((dyn exists<_dyn> [@TraitClause0_1]: NoParam<_dyn> + _dyn : '_)), &'_ ((dyn exists<_dyn> [@TraitClause0_1]: NoParam<_dyn> + _dyn : '_)), NoParam<(dyn exists<_dyn> [@TraitClause0_2]: NoParam<_dyn> + _dyn : '_)>>(move (@39)) - storage_dead(@41) - storage_dead(@39) - storage_dead(@42) - storage_dead(@40) - storage_live(@43) - storage_live(@44) - @44 := &*(z@38) with_metadata(copy (z@38.metadata)) - @43 := (move (*(@44.metadata)).method_dummy)(move (@44)) - storage_live(@92) - storage_live(@93) - @93 := const (42 : i32) - @92 := &@93 - storage_live(@94) - storage_live(@95) - @95 := const (100 : i32) - @94 := &@95 - storage_live(@96) - storage_live(@97) - @97 := const (200 : i64) - @96 := &@97 - storage_dead(@44) - storage_dead(@43) - storage_live(a@45) - storage_live(@46) - storage_live(@47) - @82 := move (@92) - @47 := &*(@82) - @46 := &*(@47) - a@45 := unsize_cast<&'_ (i32), &'_ ((dyn exists<_dyn> [@TraitClause0_1]: Both32And64<_dyn> + _dyn : '_)), {impl Both32And64 for i32}>(move (@46)) - storage_dead(@46) - storage_dead(@47) - storage_live(@48) - storage_live(@49) - @49 := &*(a@45) with_metadata(copy (a@45.metadata)) - storage_live(@50) - storage_live(@51) - @81 := move (@94) - @51 := &*(@81) - @50 := &*(@51) - storage_live(@52) - storage_live(@53) - @80 := move (@96) - @53 := &*(@80) - @52 := &*(@53) - @48 := (move (*(@49.metadata)).method_both_operate)(move (@49), move (@50), move (@52)) - storage_live(@98) - storage_live(@99) - @99 := const (42 : i32) - @98 := &@99 - storage_live(@100) - storage_live(@101) - @101 := const (10 : i32) - @100 := &@101 - storage_dead(@52) - storage_dead(@50) - storage_dead(@49) - storage_dead(@53) - storage_dead(@51) - storage_dead(@48) - storage_live(b@54) - storage_live(@55) - storage_live(@56) - @79 := move (@98) - @56 := &*(@79) - @55 := &*(@56) - b@54 := unsize_cast<&'_ (i32), &'_ ((dyn exists<_dyn> [@TraitClause0_1]: LifetimeTrait<_dyn> + _dyn : '_ + @TraitClause0_1::Ty = i32)), {impl LifetimeTrait for i32}>(move (@55)) - storage_dead(@55) - storage_dead(@56) - storage_live(@57) - storage_live(@58) - storage_live(@59) - storage_live(@60) - storage_live(@61) - @61 := &*(b@54) with_metadata(copy (b@54.metadata)) - @60 := unsize_cast<&'_ ((dyn exists<_dyn> [@TraitClause0_1]: LifetimeTrait<_dyn> + _dyn : '_ + @TraitClause0_1::Ty = i32)), &'_ ((dyn exists<_dyn> [@TraitClause0_1]: LifetimeTrait<_dyn> + _dyn : '_ + @TraitClause0_1::Ty = i32)), LifetimeTrait<(dyn exists<_dyn> [@TraitClause0_2]: LifetimeTrait<_dyn> + _dyn : '_ + @TraitClause0_2::Ty = i32)>>(move (@61)) - storage_dead(@61) - storage_live(@62) - storage_live(@63) - @78 := move (@100) - @63 := &*(@78) - @62 := &*(@63) - @59 := use_lifetime_trait<'_, '_>(move (@60), move (@62)) - storage_live(@102) - storage_live(@103) - @103 := const (10 : i32) - @102 := &@103 - storage_dead(@62) - storage_dead(@60) - @58 := &*(@59) - storage_live(@64) - @77 := move (@102) - @64 := &*(@77) - @57 := (move (@58), move (@64)) - storage_dead(@64) - storage_dead(@58) - storage_live(left_val@65) - left_val@65 := copy ((@57).0) - storage_live(right_val@66) - right_val@66 := copy ((@57).1) - storage_live(@67) - storage_live(@68) - @68 := copy (*(left_val@65)) - storage_live(@69) - @69 := copy (*(right_val@66)) - @67 := move (@68) == move (@69) - if move (@67) { + storage_dead(@4) + storage_live(y@6) + storage_live(@7) + storage_live(@8) + storage_live(@9) + @9 := const (99 : i32) + @8 := &mut @9 + @7 := &mut *(@8) + y@6 := unsize_cast<&'_ mut (i32), &'_ mut ((dyn exists<_dyn> [@TraitClause0_1]: Modifiable<_dyn, i32> + _dyn : '_)), {impl Modifiable for i32}[{built_in impl Sized for i32}, {impl Clone for i32}]>(move (@7)) + storage_dead(@7) + storage_dead(@8) + storage_live(@10) + storage_live(@11) + storage_live(@12) + storage_live(@13) + storage_live(@14) + storage_live(@15) + storage_live(@16) + storage_live(@17) + @17 := const ("Hello") + @16 := &*(@17) with_metadata(copy (@17.metadata)) + @15 := {impl ToString for T}::to_string<'_, Str>[{built_in impl MetaSized for Str}, {impl Display for Str}](move (@16)) + storage_dead(@16) + @14 := &@15 + @13 := &*(@14) + @12 := modify_trait_object<'_, String>[{built_in impl Sized for String}, {impl Clone for String}](move (@13)) + @11 := &@12 + storage_dead(@13) + @10 := is_empty<'_>(move (@11)) + if move (@10) { + storage_dead(@11) + drop[{impl Destruct for String}] @12 + drop[{impl Destruct for String}] @15 + storage_dead(@17) + storage_dead(@15) + storage_dead(@14) + storage_dead(@12) + panic(core::panicking::panic) } else { - storage_dead(@69) - storage_dead(@68) - storage_live(kind@70) - kind@70 := AssertKind::Eq { } - storage_live(@71) - @71 := move (kind@70) - storage_live(@72) - storage_live(@73) - @73 := &*(left_val@65) - @72 := &*(@73) - storage_live(@74) - storage_live(@75) - @75 := &*(right_val@66) - @74 := &*(@75) - storage_live(@76) - @76 := Option::None { } - panic(core::panicking::assert_failed) + storage_dead(@11) + drop[{impl Destruct for String}] @12 + drop[{impl Destruct for String}] @15 + storage_dead(@17) + storage_dead(@15) + storage_dead(@14) + storage_dead(@12) + storage_dead(@10) + storage_live(@18) + storage_live(@19) + storage_live(@20) + storage_live(@21) + @21 := &two-phase-mut *(y@6) with_metadata(copy (y@6.metadata)) + storage_live(@22) + storage_live(@23) + storage_live(@24) + @24 := const (100 : i32) + @23 := &mut @24 + @22 := &*(@23) + @20 := (move (*(@21.metadata)).method_modify)(move (@21), move (@22)) + storage_live(@88) + storage_live(@89) + @89 := const (100 : i32) + @88 := &@89 + storage_dead(@22) + storage_dead(@21) + @19 := &@20 + storage_live(@25) + @84 := move (@88) + @25 := &*(@84) + @18 := (move (@19), move (@25)) + storage_dead(@25) + storage_dead(@19) + storage_live(left_val@26) + left_val@26 := copy ((@18).0) + storage_live(right_val@27) + right_val@27 := copy ((@18).1) + storage_live(@28) + storage_live(@29) + @29 := copy (*(left_val@26)) + storage_live(@30) + @30 := copy (*(right_val@27)) + @28 := move (@29) == move (@30) + if move (@28) { + storage_live(@90) + storage_live(@91) + @91 := const (42 : i32) + @90 := &@91 + storage_dead(@30) + storage_dead(@29) + storage_dead(@28) + storage_dead(right_val@27) + storage_dead(left_val@26) + storage_dead(@24) + storage_dead(@23) + storage_dead(@20) + storage_dead(@18) + storage_live(z@38) + storage_live(@39) + storage_live(@40) + storage_live(@41) + storage_live(@42) + @83 := move (@90) + @42 := &*(@83) + @41 := &*(@42) + @40 := to_dyn_obj<'_, i32>[{built_in impl Sized for i32}, {impl NoParam for i32}](move (@41)) + @39 := &*(@40) with_metadata(copy (@40.metadata)) + z@38 := unsize_cast<&'_ ((dyn exists<_dyn> [@TraitClause0_1]: NoParam<_dyn> + _dyn : '_)), &'_ ((dyn exists<_dyn> [@TraitClause0_1]: NoParam<_dyn> + _dyn : '_)), NoParam<(dyn exists<_dyn> [@TraitClause0_2]: NoParam<_dyn> + _dyn : '_)>>(move (@39)) + storage_dead(@41) + storage_dead(@39) + storage_dead(@42) + storage_dead(@40) + storage_live(@43) + storage_live(@44) + @44 := &*(z@38) with_metadata(copy (z@38.metadata)) + @43 := (move (*(@44.metadata)).method_dummy)(move (@44)) + storage_live(@92) + storage_live(@93) + @93 := const (42 : i32) + @92 := &@93 + storage_live(@94) + storage_live(@95) + @95 := const (100 : i32) + @94 := &@95 + storage_live(@96) + storage_live(@97) + @97 := const (200 : i64) + @96 := &@97 + storage_dead(@44) + storage_dead(@43) + storage_live(a@45) + storage_live(@46) + storage_live(@47) + @82 := move (@92) + @47 := &*(@82) + @46 := &*(@47) + a@45 := unsize_cast<&'_ (i32), &'_ ((dyn exists<_dyn> [@TraitClause0_1]: Both32And64<_dyn> + _dyn : '_)), {impl Both32And64 for i32}>(move (@46)) + storage_dead(@46) + storage_dead(@47) + storage_live(@48) + storage_live(@49) + @49 := &*(a@45) with_metadata(copy (a@45.metadata)) + storage_live(@50) + storage_live(@51) + @81 := move (@94) + @51 := &*(@81) + @50 := &*(@51) + storage_live(@52) + storage_live(@53) + @80 := move (@96) + @53 := &*(@80) + @52 := &*(@53) + @48 := (move (*(@49.metadata)).method_both_operate)(move (@49), move (@50), move (@52)) + storage_live(@98) + storage_live(@99) + @99 := const (42 : i32) + @98 := &@99 + storage_live(@100) + storage_live(@101) + @101 := const (10 : i32) + @100 := &@101 + storage_dead(@52) + storage_dead(@50) + storage_dead(@49) + storage_dead(@53) + storage_dead(@51) + storage_dead(@48) + storage_live(b@54) + storage_live(@55) + storage_live(@56) + @79 := move (@98) + @56 := &*(@79) + @55 := &*(@56) + b@54 := unsize_cast<&'_ (i32), &'_ ((dyn exists<_dyn> [@TraitClause0_1]: LifetimeTrait<_dyn> + _dyn : '_ + @TraitClause0_1::Ty = i32)), {impl LifetimeTrait for i32}>(move (@55)) + storage_dead(@55) + storage_dead(@56) + storage_live(@57) + storage_live(@58) + storage_live(@59) + storage_live(@60) + storage_live(@61) + @61 := &*(b@54) with_metadata(copy (b@54.metadata)) + @60 := unsize_cast<&'_ ((dyn exists<_dyn> [@TraitClause0_1]: LifetimeTrait<_dyn> + _dyn : '_ + @TraitClause0_1::Ty = i32)), &'_ ((dyn exists<_dyn> [@TraitClause0_1]: LifetimeTrait<_dyn> + _dyn : '_ + @TraitClause0_1::Ty = i32)), LifetimeTrait<(dyn exists<_dyn> [@TraitClause0_2]: LifetimeTrait<_dyn> + _dyn : '_ + @TraitClause0_2::Ty = i32)>>(move (@61)) + storage_dead(@61) + storage_live(@62) + storage_live(@63) + @78 := move (@100) + @63 := &*(@78) + @62 := &*(@63) + @59 := use_lifetime_trait<'_, '_>(move (@60), move (@62)) + storage_live(@102) + storage_live(@103) + @103 := const (10 : i32) + @102 := &@103 + storage_dead(@62) + storage_dead(@60) + @58 := &*(@59) + storage_live(@64) + @77 := move (@102) + @64 := &*(@77) + @57 := (move (@58), move (@64)) + storage_dead(@64) + storage_dead(@58) + storage_live(left_val@65) + left_val@65 := copy ((@57).0) + storage_live(right_val@66) + right_val@66 := copy ((@57).1) + storage_live(@67) + storage_live(@68) + @68 := copy (*(left_val@65)) + storage_live(@69) + @69 := copy (*(right_val@66)) + @67 := move (@68) == move (@69) + if move (@67) { + storage_dead(@69) + storage_dead(@68) + storage_dead(@67) + storage_dead(right_val@66) + storage_dead(left_val@65) + storage_dead(@63) + storage_dead(@59) + storage_dead(@57) + @0 := () + storage_dead(b@54) + storage_dead(a@45) + storage_dead(z@38) + storage_dead(@9) + storage_dead(y@6) + storage_dead(x@1) + return + } + else { + storage_dead(@69) + storage_dead(@68) + storage_live(kind@70) + kind@70 := AssertKind::Eq { } + storage_live(@71) + @71 := move (kind@70) + storage_live(@72) + storage_live(@73) + @73 := &*(left_val@65) + @72 := &*(@73) + storage_live(@74) + storage_live(@75) + @75 := &*(right_val@66) + @74 := &*(@75) + storage_live(@76) + @76 := Option::None { } + panic(core::panicking::assert_failed) + } + } + else { + storage_dead(@30) + storage_dead(@29) + storage_live(kind@31) + kind@31 := AssertKind::Eq { } + storage_live(@32) + @32 := move (kind@31) + storage_live(@33) + storage_live(@34) + @34 := &*(left_val@26) + @33 := &*(@34) + storage_live(@35) + storage_live(@36) + @36 := &*(right_val@27) + @35 := &*(@36) + storage_live(@37) + @37 := Option::None { } + panic(core::panicking::assert_failed) + } } - storage_dead(@69) - storage_dead(@68) - storage_dead(@67) - storage_dead(right_val@66) - storage_dead(left_val@65) - storage_dead(@63) - storage_dead(@59) - storage_dead(@57) - @0 := () - storage_dead(b@54) - storage_dead(a@45) - storage_dead(z@38) - storage_dead(@9) - storage_dead(y@6) - storage_dead(x@1) - return } - storage_dead(@11) - drop[{impl Destruct for String}] @12 - drop[{impl Destruct for String}] @15 - storage_dead(@17) - storage_dead(@15) - storage_dead(@14) - storage_dead(@12) - panic(core::panicking::panic) + else { + storage_dead(@5) + panic(core::panicking::panic) + } }