Repository: Qiskit/qiskit-terra (python)

Issue:
Qasm3 exporter failing when if branch does not contain all clbits
### Environment

- **Qiskit Terra version**: 0.39.0
- **Python version**: 3.10.6
- **Operating system**: MacOs 12.6 (21G115)


### What is happening?

In some cases, the qasm3 exporter gives an error if the circuit has more clbits than needed in the if_else statement.

### How can we reproduce the issue?

Run the following:

```
backend_wellington = provider.get_backend('ibm_wellington')

cr = ClassicalRegister(1) # if >1 breaks
cr2 = ClassicalRegister(1) # if this reg exists, breaks
qr = QuantumRegister(5)
qc = QuantumCircuit(qr, cr, cr2)

with qc.if_test((cr[0], 1)) as _:
    qc.cnot(0,1)
    qc.cnot(0,2)
    qc.cnot(0,3)
    qc.cnot(0,4)

qc_trans = transpile(qc, backend=backend_wellington, basis_gates=backend_wellington.configuration().basis_gates+['if_else'], optimization_level=1)
print(qasm3.Exporter().dumps(qc))
print(qasm3.Exporter().dumps(qc_trans))
```

Now, `qc` gets correctly exported, while `qc_trans` provides the following error:
```
QASM3ExporterError: 'Tried to push a scope whose circuit needs 2 clbits, but only provided 1 clbits to create the mapping.'
```

### What should happen?

The QASM3 string should be output for both cases.

### Any suggestions?

_No response_

Pull request description:
Fix classical-bit handling in control-flow StochasticSwap
### Summary

Previously we were expanding control-flow blocks to be full-width over _all_ wires, and only contracting the qubits back again, without changing the clbits given as node arguments.  This modifies the

The changes in most of the tests are necessary because the tests were testing behaviour that should be considered incorrect.  The principal new test of all this behaviour is the additional assertions added in `_visit_block` in the random tests; these uniformly fail without this patch, and succeed with it.

<!--
⚠️ If you do not respect this template, your pull request will be closed.
⚠️ Your pull request title should be short detailed and understandable for all.
⚠️ Also, please add a release note file using reno if the change needs to be
  documented in the release notes.
⚠️ If your pull request fixes an open issue, please link to the issue.

- [ ] I have added the tests to cover my changes.
- [ ] I have updated the documentation accordingly.
- [ ] I have read the CONTRIBUTING document.
-->


### Details and comments

Fix #8903.



Patch:
diff --git a/qiskit/transpiler/passes/routing/stochastic_swap.py b/qiskit/transpiler/passes/routing/stochastic_swap.py
index 13fd6afb1..dde788f3d 100644
--- a/qiskit/transpiler/passes/routing/stochastic_swap.py
+++ b/qiskit/transpiler/passes/routing/stochastic_swap.py
@@ -12,6 +12,7 @@
 
 """Map a DAGCircuit onto a `coupling_map` adding swap gates."""
 
+import itertools
 import logging
 from math import inf
 import numpy as np
@@ -23,7 +24,7 @@ from qiskit.transpiler.exceptions import TranspilerError
 from qiskit.dagcircuit import DAGCircuit
 from qiskit.circuit.library.standard_gates import SwapGate
 from qiskit.transpiler.layout import Layout
-from qiskit.circuit import IfElseOp, WhileLoopOp, ForLoopOp, ControlFlowOp
+from qiskit.circuit import IfElseOp, WhileLoopOp, ForLoopOp, ControlFlowOp, Instruction
 from qiskit._accelerate import stochastic_swap as stochastic_swap_rs
 
 from .utils import get_swap_map_dag
@@ -380,9 +381,7 @@ class StochasticSwap(TransformationPass):
         block_layouts = []
         for block in node.op.blocks:
             inner_pass = self._recursive_pass(current_layout)
-            full_dag_block = root_dag.copy_empty_like()
-            full_dag_block.compose(circuit_to_dag(block), qubits=node.qargs)
-            block_dags.append(inner_pass.run(full_dag_block))
+            block_dags.append(inner_pass.run(_dag_from_block(block, node, root_dag)))
             block_layouts.append(inner_pass.property_set["final_layout"].copy())
 
         # Determine what layout we need to go towards.  For some blocks (such as `for`), we must
@@ -443,3 +442,23 @@ class StochasticSwap(TransformationPass):
             fake_run=self.fake_run,
             initial_layout=initial_layout,
         )
+
+
+def _dag_from_block(block, node, root_dag):
+    """Get a :class:`DAGCircuit` that represents the :class:`.QuantumCircuit` ``block`` embedded
+    within the ``root_dag`` for full-width routing purposes.  This means that all the qubits are in
+    the output DAG, but only the necessary clbits and classical registers are."""
+    out = DAGCircuit()
+    # The pass already ensured that `root_dag` has only a single quantum register with everything.
+    for qreg in root_dag.qregs.values():
+        out.add_qreg(qreg)
+    # For clbits, we need to take more care.  Nested control-flow might need registers to exist for
+    # conditions on inner blocks.  `DAGCircuit.substitute_node_with_dag` handles this register
+    # mapping when required, so we use that with a dummy block.
+    out.add_clbits(node.cargs)
+    dummy = out.apply_operation_back(
+        Instruction("dummy", len(node.qargs), len(node.cargs), []), node.qargs, node.cargs
+    )
+    wire_map = dict(itertools.chain(zip(block.qubits, node.qargs), zip(block.clbits, node.cargs)))
+    out.substitute_node_with_dag(dummy, circuit_to_dag(block), wires=wire_map)
+    return out
diff --git a/releasenotes/notes/fix-clbit-handling-stochasticswap-controlflow-fbb9d8fab5040643.yaml b/releasenotes/notes/fix-clbit-handling-stochasticswap-controlflow-fbb9d8fab5040643.yaml
new file mode 100644
index 000000000..b767e04bd
--- /dev/null
+++ b/releasenotes/notes/fix-clbit-handling-stochasticswap-controlflow-fbb9d8fab5040643.yaml
@@ -0,0 +1,8 @@
+---
+fixes:
+  - |
+    Fixed handling of classical bits in :class:`.StochasticSwap` with control flow.
+    Previously, control-flow operations would be expanded to contain all the
+    classical bits in the outer circuit and not contracted again, leading to a
+    mismatch between the numbers of clbits the instruction reported needing and
+    the actual number supplied to it.


Test patch:
diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py
index 0a9f2027e..8ab952b6f 100644
--- a/test/python/compiler/test_transpiler.py
+++ b/test/python/compiler/test_transpiler.py
@@ -27,7 +27,7 @@ import numpy as np
 
 from qiskit.exceptions import QiskitError
 from qiskit import BasicAer
-from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit, pulse
+from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit, pulse, qpy, qasm3
 from qiskit.circuit import Parameter, Gate, Qubit, Clbit
 from qiskit.compiler import transpile
 from qiskit.dagcircuit import DAGOutNode
@@ -62,6 +62,17 @@ from qiskit.transpiler.passmanager_config import PassManagerConfig
 from qiskit.transpiler.preset_passmanagers import level_0_pass_manager
 
 
+class CustomCX(Gate):
+    """Custom CX gate representation."""
+
+    def __init__(self):
+        super().__init__("custom_cx", 2, [])
+
+    def _define(self):
+        self._definition = QuantumCircuit(2)
+        self._definition.cx(0, 1)
+
+
 @ddt
 class TestTranspile(QiskitTestCase):
     """Test transpile function."""
@@ -1490,16 +1501,6 @@ class TestTranspile(QiskitTestCase):
         target.add_instruction(WhileLoopOp, name="while_loop")
         target.add_instruction(IfElseOp, name="if_else")
 
-        class CustomCX(Gate):
-            """Custom CX"""
-
-            def __init__(self):
-                super().__init__("custom_cx", 2, [])
-
-            def _define(self):
-                self._definition = QuantumCircuit(2)
-                self._definition.cx(0, 1)
-
         circuit = QuantumCircuit(6, 1)
         circuit.h(0)
         circuit.measure(0, 0)
@@ -1554,6 +1555,177 @@ class TestTranspile(QiskitTestCase):
         )
 
 
+@ddt
+class TestPostTranspileIntegration(QiskitTestCase):
+    """Test that the output of `transpile` is usable in various other integration contexts."""
+
+    def _regular_circuit(self):
+        a = Parameter("a")
+        regs = [
+            QuantumRegister(2, name="q0"),
+            QuantumRegister(3, name="q1"),
+            ClassicalRegister(2, name="c0"),
+        ]
+        bits = [Qubit(), Qubit(), Clbit()]
+        base = QuantumCircuit(*regs, bits)
+        base.h(0)
+        base.measure(0, 0)
+        base.cx(0, 1)
+        base.cz(0, 2)
+        base.cz(0, 3)
+        base.cz(1, 4)
+        base.cx(1, 5)
+        base.measure(1, 1)
+        base.append(CustomCX(), [3, 6])
+        base.append(CustomCX(), [5, 4])
+        base.append(CustomCX(), [5, 3])
+        base.append(CustomCX(), [2, 4]).c_if(base.cregs[0], 3)
+        base.ry(a, 4)
+        base.measure(4, 2)
+        return base
+
+    def _control_flow_circuit(self):
+        a = Parameter("a")
+        regs = [
+            QuantumRegister(2, name="q0"),
+            QuantumRegister(3, name="q1"),
+            ClassicalRegister(2, name="c0"),
+        ]
+        bits = [Qubit(), Qubit(), Clbit()]
+        base = QuantumCircuit(*regs, bits)
+        base.h(0)
+        base.measure(0, 0)
+        with base.if_test((base.cregs[0], 1)) as else_:
+            base.cx(0, 1)
+            base.cz(0, 2)
+            base.cz(0, 3)
+        with else_:
+            base.cz(1, 4)
+            with base.for_loop((1, 2)):
+                base.cx(1, 5)
+        base.measure(2, 2)
+        with base.while_loop((2, False)):
+            base.append(CustomCX(), [3, 6])
+            base.append(CustomCX(), [5, 4])
+            base.append(CustomCX(), [5, 3])
+            base.append(CustomCX(), [2, 4])
+            base.ry(a, 4)
+            base.measure(4, 2)
+        return base
+
+    @data(0, 1, 2, 3)
+    def test_qpy_roundtrip(self, optimization_level):
+        """Test that the output of a transpiled circuit can be round-tripped through QPY."""
+        transpiled = transpile(
+            self._regular_circuit(),
+            backend=FakeMelbourne(),
+            optimization_level=optimization_level,
+            seed_transpiler=2022_10_17,
+        )
+        # Round-tripping the layout is out-of-scope for QPY while it's a private attribute.
+        transpiled._layout = None
+        buffer = io.BytesIO()
+        qpy.dump(transpiled, buffer)
+        buffer.seek(0)
+        round_tripped = qpy.load(buffer)[0]
+        self.assertEqual(round_tripped, transpiled)
+
+    @data(0, 1, 2, 3)
+    def test_qpy_roundtrip_backendv2(self, optimization_level):
+        """Test that the output of a transpiled circuit can be round-tripped through QPY."""
+        transpiled = transpile(
+            self._regular_circuit(),
+            backend=FakeMumbaiV2(),
+            optimization_level=optimization_level,
+            seed_transpiler=2022_10_17,
+        )
+
+        # Round-tripping the layout is out-of-scope for QPY while it's a private attribute.
+        transpiled._layout = None
+        buffer = io.BytesIO()
+        qpy.dump(transpiled, buffer)
+        buffer.seek(0)
+        round_tripped = qpy.load(buffer)[0]
+
+        self.assertEqual(round_tripped, transpiled)
+
+    @data(0, 1)
+    def test_qpy_roundtrip_control_flow(self, optimization_level):
+        """Test that the output of a transpiled circuit with control flow can be round-tripped
+        through QPY."""
+
+        backend = FakeMelbourne()
+        transpiled = transpile(
+            self._control_flow_circuit(),
+            backend=backend,
+            basis_gates=backend.configuration().basis_gates + ["if_else", "for_loop", "while_loop"],
+            optimization_level=optimization_level,
+            seed_transpiler=2022_10_17,
+        )
+        # Round-tripping the layout is out-of-scope for QPY while it's a private attribute.
+        transpiled._layout = None
+        buffer = io.BytesIO()
+        qpy.dump(transpiled, buffer)
+        buffer.seek(0)
+        round_tripped = qpy.load(buffer)[0]
+        self.assertEqual(round_tripped, transpiled)
+
+    @data(0, 1)
+    def test_qpy_roundtrip_control_flow_backendv2(self, optimization_level):
+        """Test that the output of a transpiled circuit with control flow can be round-tripped
+        through QPY."""
+        backend = FakeMumbaiV2()
+        backend.target.add_instruction(IfElseOp, name="if_else")
+        backend.target.add_instruction(ForLoopOp, name="for_loop")
+        backend.target.add_instruction(WhileLoopOp, name="while_loop")
+        transpiled = transpile(
+            self._control_flow_circuit(),
+            backend=backend,
+            optimization_level=optimization_level,
+            seed_transpiler=2022_10_17,
+        )
+        # Round-tripping the layout is out-of-scope for QPY while it's a private attribute.
+        transpiled._layout = None
+        buffer = io.BytesIO()
+        qpy.dump(transpiled, buffer)
+        buffer.seek(0)
+        round_tripped = qpy.load(buffer)[0]
+        self.assertEqual(round_tripped, transpiled)
+
+    @data(0, 1, 2, 3)
+    def test_qasm3_output(self, optimization_level):
+        """Test that the output of a transpiled circuit can be dumped into OpenQASM 3."""
+        transpiled = transpile(
+            self._regular_circuit(),
+            backend=FakeMelbourne(),
+            optimization_level=optimization_level,
+            seed_transpiler=2022_10_17,
+        )
+        # TODO: There's not a huge amount we can sensibly test for the output here until we can
+        # round-trip the OpenQASM 3 back into a Terra circuit.  Mostly we're concerned that the dump
+        # itself doesn't throw an error, though.
+        self.assertIsInstance(qasm3.dumps(transpiled).strip(), str)
+
+    @data(0, 1)
+    def test_qasm3_output_control_flow(self, optimization_level):
+        """Test that the output of a transpiled circuit with control flow can be dumped into
+        OpenQASM 3."""
+        backend = FakeMumbaiV2()
+        backend.target.add_instruction(IfElseOp, name="if_else")
+        backend.target.add_instruction(ForLoopOp, name="for_loop")
+        backend.target.add_instruction(WhileLoopOp, name="while_loop")
+        transpiled = transpile(
+            self._control_flow_circuit(),
+            backend=backend,
+            optimization_level=optimization_level,
+            seed_transpiler=2022_10_17,
+        )
+        # TODO: There's not a huge amount we can sensibly test for the output here until we can
+        # round-trip the OpenQASM 3 back into a Terra circuit.  Mostly we're concerned that the dump
+        # itself doesn't throw an error, though.
+        self.assertIsInstance(qasm3.dumps(transpiled).strip(), str)
+
+
 class StreamHandlerRaiseException(StreamHandler):
     """Handler class that will raise an exception on formatting errors."""
 
diff --git a/test/python/transpiler/test_stochastic_swap.py b/test/python/transpiler/test_stochastic_swap.py
index da37210a8..0b1cdfea1 100644
--- a/test/python/transpiler/test_stochastic_swap.py
+++ b/test/python/transpiler/test_stochastic_swap.py
@@ -591,11 +591,11 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         qc.h(0)
         qc.cx(0, 2)
         qc.measure(2, 2)
-        true_body = QuantumCircuit(qreg, creg)
+        true_body = QuantumCircuit(qreg, creg[[2]])
         true_body.x(3)
-        false_body = QuantumCircuit(qreg, creg)
+        false_body = QuantumCircuit(qreg, creg[[2]])
         false_body.x(4)
-        qc.if_else((creg[2], 0), true_body, false_body, qreg, creg)
+        qc.if_else((creg[2], 0), true_body, false_body, qreg, creg[[2]])
         qc.barrier(qreg)
         qc.measure(qreg, creg)
 
@@ -610,12 +610,12 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         expected.swap(0, 1)
         expected.cx(1, 2)
         expected.measure(2, 2)
-        etrue_body = QuantumCircuit(qreg[[3, 4]], creg)
+        etrue_body = QuantumCircuit(qreg[[3, 4]], creg[[2]])
         etrue_body.x(0)
-        efalse_body = QuantumCircuit(qreg[[3, 4]], creg)
+        efalse_body = QuantumCircuit(qreg[[3, 4]], creg[[2]])
         efalse_body.x(1)
         new_order = [1, 0, 2, 3, 4]
-        expected.if_else((creg[2], 0), etrue_body, efalse_body, qreg[[3, 4]], creg)
+        expected.if_else((creg[2], 0), etrue_body, efalse_body, qreg[[3, 4]], creg[[2]])
         expected.barrier(qreg)
         expected.measure(qreg, creg[new_order])
         self.assertEqual(dag_to_circuit(cdag), expected)
@@ -630,11 +630,11 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         qc.h(0)
         qc.cx(0, 2)
         qc.measure(2, 2)
-        true_body = QuantumCircuit(qreg, creg)
+        true_body = QuantumCircuit(qreg, creg[[0]])
         true_body.x(3)
-        false_body = QuantumCircuit(qreg, creg)
+        false_body = QuantumCircuit(qreg, creg[[0]])
         false_body.x(4)
-        qc.if_else((creg[2], 0), true_body, false_body, qreg, creg)
+        qc.if_else((creg[2], 0), true_body, false_body, qreg, creg[[0]])
         qc.x(1)
         qc.barrier(qreg)
         qc.measure(qreg, creg)
@@ -651,11 +651,11 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         expected.cx(0, 1)
         expected.measure(1, 2)
         new_order = [0, 2, 1, 3, 4]
-        etrue_body = QuantumCircuit(qreg[[3, 4]], creg)
+        etrue_body = QuantumCircuit(qreg[[3, 4]], creg[[0]])
         etrue_body.x(0)
-        efalse_body = QuantumCircuit(qreg[[3, 4]], creg)
+        efalse_body = QuantumCircuit(qreg[[3, 4]], creg[[0]])
         efalse_body.x(1)
-        expected.if_else((creg[2], 0), etrue_body, efalse_body, qreg[[3, 4]], creg)
+        expected.if_else((creg[2], 0), etrue_body, efalse_body, qreg[[3, 4]], creg[[0]])
         expected.x(2)
         expected.barrier(qreg)
         expected.measure(qreg, creg[new_order])
@@ -670,12 +670,12 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         qc = QuantumCircuit(qreg, creg)
         qc.h(0)
         qc.measure(0, 0)
-        true_body = QuantumCircuit(qreg, creg)
+        true_body = QuantumCircuit(qreg, creg[[0]])
         true_body.x(3)
-        false_body = QuantumCircuit(qreg, creg)
+        false_body = QuantumCircuit(qreg, creg[[0]])
         false_body.x(4)
         qc.barrier(qreg)
-        qc.if_else((creg[0], 0), true_body, false_body, qreg, creg)
+        qc.if_else((creg[0], 0), true_body, false_body, qreg, creg[[0]])
         qc.barrier(qreg)
         qc.cx(0, 2)
         qc.barrier(qreg)
@@ -690,12 +690,12 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         expected = QuantumCircuit(qreg, creg)
         expected.h(0)
         expected.measure(0, 0)
-        etrue_body = QuantumCircuit(qreg[[3, 4]], creg)
+        etrue_body = QuantumCircuit(qreg[[3, 4]], creg[[0]])
         etrue_body.x(0)
-        efalse_body = QuantumCircuit(qreg[[3, 4]], creg)
+        efalse_body = QuantumCircuit(qreg[[3, 4]], creg[[0]])
         efalse_body.x(1)
         expected.barrier(qreg)
-        expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg[[3, 4]], creg)
+        expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg[[3, 4]], creg[[0]])
         expected.barrier(qreg)
         expected.swap(0, 1)
         expected.cx(1, 2)
@@ -714,10 +714,10 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         qc.cx(0, 2)
         qc.x(1)
         qc.measure(0, 0)
-        true_body = QuantumCircuit(qreg, creg)
+        true_body = QuantumCircuit(qreg, creg[[0]])
         true_body.x(0)
-        false_body = QuantumCircuit(qreg, creg)
-        qc.if_else((creg[0], 0), true_body, false_body, qreg, creg)
+        false_body = QuantumCircuit(qreg, creg[[0]])
+        qc.if_else((creg[0], 0), true_body, false_body, qreg, creg[[0]])
         qc.barrier(qreg)
         qc.measure(qreg, creg)
 
@@ -733,11 +733,11 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         expected.swap(0, 1)
         expected.cx(1, 2)
         expected.measure(1, 0)
-        etrue_body = QuantumCircuit(qreg[[1]], creg)
+        etrue_body = QuantumCircuit(qreg[[1]], creg[[0]])
         etrue_body.x(0)
-        efalse_body = QuantumCircuit(qreg[[1]], creg)
+        efalse_body = QuantumCircuit(qreg[[1]], creg[[0]])
         new_order = [1, 0, 2, 3, 4]
-        expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg[[1]], creg)
+        expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg[[1]], creg[[0]])
         expected.barrier(qreg)
         expected.measure(qreg, creg[new_order])
         self.assertEqual(dag_to_circuit(cdag), expected)
@@ -752,11 +752,11 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         qc.h(0)
         qc.x(1)
         qc.measure(0, 0)
-        true_body = QuantumCircuit(qreg, creg)
+        true_body = QuantumCircuit(qreg, creg[[0]])
         true_body.cx(0, 2)
-        false_body = QuantumCircuit(qreg, creg)
+        false_body = QuantumCircuit(qreg, creg[[0]])
         false_body.cx(0, 4)
-        qc.if_else((creg[0], 0), true_body, false_body, qreg, creg)
+        qc.if_else((creg[0], 0), true_body, false_body, qreg, creg[[0]])
         qc.measure(qreg, creg)
 
         dag = circuit_to_dag(qc)
@@ -769,17 +769,17 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         expected.h(0)
         expected.x(1)
         expected.measure(0, 0)
-        etrue_body = QuantumCircuit(qreg, creg)
+        etrue_body = QuantumCircuit(qreg, creg[[0]])
         etrue_body.swap(0, 1)
         etrue_body.cx(1, 2)
         etrue_body.swap(1, 2)
         etrue_body.swap(3, 4)
-        efalse_body = QuantumCircuit(qreg, creg)
+        efalse_body = QuantumCircuit(qreg, creg[[0]])
         efalse_body.swap(0, 1)
         efalse_body.swap(1, 2)
         efalse_body.swap(3, 4)
         efalse_body.cx(2, 3)
-        expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg, creg)
+        expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg, creg[[0]])
         new_order = [1, 2, 0, 4, 3]
         expected.measure(qreg, creg[new_order])
         self.assertEqual(dag_to_circuit(cdag), expected)
@@ -795,11 +795,11 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         qc.cx(0, 2)
         qc.x(1)
         qc.measure(0, 0)
-        true_body = QuantumCircuit(qreg, creg)
+        true_body = QuantumCircuit(qreg, creg[[0]])
         true_body.cx(0, 2)
-        false_body = QuantumCircuit(qreg, creg)
+        false_body = QuantumCircuit(qreg, creg[[0]])
         false_body.cx(0, 4)
-        qc.if_else((creg[0], 0), true_body, false_body, qreg, creg)
+        qc.if_else((creg[0], 0), true_body, false_body, qreg, creg[[0]])
         qc.measure(qreg, creg)
 
         dag = circuit_to_dag(qc)
@@ -809,8 +809,8 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         self.assertTrue(check_map_pass.property_set["is_swap_mapped"])
 
         expected = QuantumCircuit(qreg, creg)
-        etrue_body = QuantumCircuit(qreg[[1, 2, 3, 4]], creg)
-        efalse_body = QuantumCircuit(qreg[[1, 2, 3, 4]], creg)
+        etrue_body = QuantumCircuit(qreg[[1, 2, 3, 4]], creg[[0]])
+        efalse_body = QuantumCircuit(qreg[[1, 2, 3, 4]], creg[[0]])
         expected.h(0)
         expected.x(1)
         expected.swap(0, 1)
@@ -824,7 +824,7 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         efalse_body.swap(0, 1)
         efalse_body.swap(2, 3)
         efalse_body.cx(1, 2)
-        expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg[[1, 2, 3, 4]], creg)
+        expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg[[1, 2, 3, 4]], creg[[0]])
         expected.measure(qreg, creg[[1, 2, 0, 4, 3]])
         self.assertEqual(dag_to_circuit(cdag), expected)
 
@@ -840,11 +840,11 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         qc.cx(0, 2)
         qc.x(1)
         qc.measure(0, 0)
-        true_body = QuantumCircuit(qreg, creg)
+        true_body = QuantumCircuit(qreg, creg[[0]])
         true_body.cx(0, 2)
-        false_body = QuantumCircuit(qreg, creg)
+        false_body = QuantumCircuit(qreg, creg[[0]])
         false_body.cx(0, 4)
-        qc.if_else((creg[0], 0), true_body, false_body, qreg, creg)
+        qc.if_else((creg[0], 0), true_body, false_body, qreg, creg[[0]])
         qc.h(3)
         qc.cx(3, 0)
         qc.barrier()
@@ -862,17 +862,17 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         expected.swap(1, 2)
         expected.cx(0, 1)
         expected.measure(0, 0)
-        etrue_body = QuantumCircuit(qreg, creg)
+        etrue_body = QuantumCircuit(qreg, creg[[0]])
         etrue_body.cx(0, 1)
         etrue_body.swap(0, 1)
         etrue_body.swap(4, 3)
         etrue_body.swap(2, 3)
-        efalse_body = QuantumCircuit(qreg, creg)
+        efalse_body = QuantumCircuit(qreg, creg[[0]])
         efalse_body.swap(0, 1)
         efalse_body.swap(3, 4)
         efalse_body.swap(2, 3)
         efalse_body.cx(1, 2)
-        expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg[[0, 1, 2, 3, 4]], creg)
+        expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg[[0, 1, 2, 3, 4]], creg[[0]])
         expected.swap(1, 2)
         expected.h(4)
         expected.swap(3, 4)
@@ -892,11 +892,11 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         qc.cx(0, 2)
         qc.x(1)
         qc.measure(0, 0)
-        true_body = QuantumCircuit(qreg, creg)
+        true_body = QuantumCircuit(qreg, creg[[0]])
         true_body.x(2)
-        false_body = QuantumCircuit(qreg, creg)
+        false_body = QuantumCircuit(qreg, creg[[0]])
         false_body.x(4)
-        qc.if_else((creg[0], 0), true_body, false_body, qreg, creg)
+        qc.if_else((creg[0], 0), true_body, false_body, qreg, creg[[0]])
         qc.barrier(qreg)
         qc.measure(qreg, creg)
 
@@ -912,11 +912,11 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         expected.swap(1, 2)
         expected.cx(0, 1)
         expected.measure(0, 0)
-        etrue_body = QuantumCircuit(qreg[[1, 4]], creg)
+        etrue_body = QuantumCircuit(qreg[[1, 4]], creg[[0]])
         etrue_body.x(0)
-        efalse_body = QuantumCircuit(qreg[[1, 4]], creg)
+        efalse_body = QuantumCircuit(qreg[[1, 4]], creg[[0]])
         efalse_body.x(1)
-        expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg[[1, 4]], creg)
+        expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg[[1, 4]], creg[[0]])
         expected.barrier(qreg)
         expected.measure(qreg, creg[[0, 2, 1, 3, 4]])
         self.assertEqual(dag_to_circuit(cdag), expected)
@@ -934,10 +934,10 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         qc = QuantumCircuit(qreg, creg)
         qc.h(0)
         qc.x(1)
-        for_body = QuantumCircuit(qreg, creg)
+        for_body = QuantumCircuit(qreg)
         for_body.cx(0, 2)
         loop_parameter = None
-        qc.for_loop(range(nloops), loop_parameter, for_body, qreg, creg)
+        qc.for_loop(range(nloops), loop_parameter, for_body, qreg, [])
         qc.measure(qreg, creg)
 
         dag = circuit_to_dag(qc)
@@ -949,12 +949,12 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         expected = QuantumCircuit(qreg, creg)
         expected.h(0)
         expected.x(1)
-        efor_body = QuantumCircuit(qreg, creg)
+        efor_body = QuantumCircuit(qreg)
         efor_body.swap(0, 1)
         efor_body.cx(1, 2)
         efor_body.swap(0, 1)
         loop_parameter = None
-        expected.for_loop(range(nloops), loop_parameter, efor_body, qreg, creg)
+        expected.for_loop(range(nloops), loop_parameter, efor_body, qreg, [])
         expected.measure(qreg, creg)
         self.assertEqual(dag_to_circuit(cdag), expected)
 
@@ -981,7 +981,7 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         self.assertTrue(check_map_pass.property_set["is_swap_mapped"])
 
         expected = QuantumCircuit(qreg, creg)
-        ewhile_body = QuantumCircuit(qreg, creg)
+        ewhile_body = QuantumCircuit(qreg, creg[:])
         ewhile_body.reset(qreg[2:])
         ewhile_body.h(qreg[2:])
         ewhile_body.swap(0, 1)
@@ -1007,19 +1007,19 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         qc.h(0)
         qc.x(1)
         qc.measure(0, 0)
-        true_body = QuantumCircuit(qreg, creg)
+        true_body = QuantumCircuit(qreg, creg[[0]])
         true_body.x(0)
 
-        for_body = QuantumCircuit(qreg, creg)
+        for_body = QuantumCircuit(qreg)
         for_body.delay(10, 0)
         for_body.barrier(qreg)
         for_body.cx(0, 2)
         loop_parameter = None
-        true_body.for_loop(range(3), loop_parameter, for_body, qreg, creg)
+        true_body.for_loop(range(3), loop_parameter, for_body, qreg, [])
 
-        false_body = QuantumCircuit(qreg, creg)
+        false_body = QuantumCircuit(qreg, creg[[0]])
         false_body.y(0)
-        qc.if_else((creg[0], 0), true_body, false_body, qreg, creg)
+        qc.if_else((creg[0], 0), true_body, false_body, qreg, creg[[0]])
         qc.measure(qreg, creg)
 
         dag = circuit_to_dag(qc)
@@ -1032,20 +1032,20 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         expected.h(0)
         expected.x(1)
         expected.measure(0, 0)
-        etrue_body = QuantumCircuit(qreg, creg)
+        etrue_body = QuantumCircuit(qreg, creg[[0]])
         etrue_body.x(0)
 
-        efor_body = QuantumCircuit(qreg, creg)
+        efor_body = QuantumCircuit(qreg)
         efor_body.delay(10, 0)
         efor_body.barrier(qreg)
         efor_body.swap(1, 2)
         efor_body.cx(0, 1)
         efor_body.swap(1, 2)
-        etrue_body.for_loop(range(3), loop_parameter, efor_body, qreg, creg)
+        etrue_body.for_loop(range(3), loop_parameter, efor_body, qreg, [])
 
-        efalse_body = QuantumCircuit(qreg, creg)
+        efalse_body = QuantumCircuit(qreg, creg[[0]])
         efalse_body.y(0)
-        expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg, creg)
+        expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg, creg[[0]])
         expected.measure(qreg, creg)
 
         self.assertEqual(dag_to_circuit(cdag), expected)
@@ -1061,20 +1061,20 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         qc.h(0)
         qc.x(1)
         qc.measure(0, 0)
-        true_body = QuantumCircuit(qreg, creg)
+        true_body = QuantumCircuit(qreg, creg[[0]])
         true_body.cx(0, 2)
         true_body.x(0)
 
-        for_body = QuantumCircuit(qreg, creg)
+        for_body = QuantumCircuit(qreg)
         for_body.delay(10, 0)
         for_body.barrier(qreg)
         for_body.cx(1, 3)
         loop_parameter = None
-        true_body.for_loop(range(3), loop_parameter, for_body, qreg, creg)
+        true_body.for_loop(range(3), loop_parameter, for_body, qreg, [])
 
-        false_body = QuantumCircuit(qreg, creg)
+        false_body = QuantumCircuit(qreg, creg[[0]])
         false_body.y(0)
-        qc.if_else((creg[0], 0), true_body, false_body, qreg, creg)
+        qc.if_else((creg[0], 0), true_body, false_body, qreg, creg[[0]])
         qc.measure(qreg, creg)
 
         dag = circuit_to_dag(qc)
@@ -1087,21 +1087,21 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         expected.h(0)
         expected.x(1)
         expected.measure(0, 0)
-        etrue_body = QuantumCircuit(qreg, creg)
+        etrue_body = QuantumCircuit(qreg, creg[[0]])
         etrue_body.swap(1, 2)
         etrue_body.cx(0, 1)
         etrue_body.x(0)
 
-        efor_body = QuantumCircuit(qreg, creg)
+        efor_body = QuantumCircuit(qreg)
         efor_body.delay(10, 0)
         efor_body.barrier(qreg)
         efor_body.cx(2, 3)
-        etrue_body.for_loop(range(3), loop_parameter, efor_body, qreg[[0, 1, 2, 3, 4]], creg)
+        etrue_body.for_loop(range(3), loop_parameter, efor_body, qreg[[0, 1, 2, 3, 4]], [])
 
-        efalse_body = QuantumCircuit(qreg, creg)
+        efalse_body = QuantumCircuit(qreg, creg[[0]])
         efalse_body.y(0)
         efalse_body.swap(1, 2)
-        expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg, creg)
+        expected.if_else((creg[0], 0), etrue_body, efalse_body, qreg, creg[[0]])
         expected.measure(qreg, creg[[0, 2, 1, 3, 4]])
         self.assertEqual(dag_to_circuit(cdag), expected)
 
@@ -1135,17 +1135,17 @@ class TestStochasticSwapControlFlow(QiskitTestCase):
         true_body.cx(0, 1)
         false_body = QuantumCircuit(3, 1)
         false_body.cx(0, 2)
-        qc.if_else((cr[0], 1), true_body, false_body, [0, 1, 2], [])
+        qc.if_else((cr[0], 1), true_body, false_body, [0, 1, 2], [0])
         cqc = StochasticSwap(cm, seed=353)(qc)
 
         expected = QuantumCircuit(qr, cr)
-        etrue_body = QuantumCircuit(qr[[0, 1, 2]], cr)
+        etrue_body = QuantumCircuit(qr[[0, 1, 2]], cr[[0]])
         etrue_body.cx(0, 1)
         etrue_body.swap(0, 1)
-        efalse_body = QuantumCircuit(qr[[0, 1, 2]], cr)
+        efalse_body = QuantumCircuit(qr[[0, 1, 2]], cr[[0]])
         efalse_body.swap(0, 1)
         efalse_body.cx(1, 2)
-        expected.if_else((cr[0], 1), etrue_body, efalse_body, [0, 1, 2], [])
+        expected.if_else((cr[0], 1), etrue_body, efalse_body, [0, 1, 2], cr[[0]])
         self.assertEqual(cqc, expected)
 
     def test_multiple_ops_per_layer(self):
@@ -1239,8 +1239,10 @@ class TestStochasticSwapRandomCircuitValidOutput(QiskitTestCase):
                         self.assertIn(qargs, self.coupling_edge_set)
                     else:
                         self.assertLessEqual(qargs[0], 26)
-                if isinstance(instruction.operation, ControlFlowOp):
+                else:
                     for block in instruction.operation.blocks:
+                        self.assertEqual(block.num_qubits, len(instruction.qubits))
+                        self.assertEqual(block.num_clbits, len(instruction.clbits))
                         new_mapping = {
                             inner: qubit_mapping[outer]
                             for outer, inner in zip(instruction.qubits, block.qubits)