Repository: Qiskit/qiskit

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_


Discussion:
@jakelishman FYI
Thanks for the report, though please don't tag me in everything - I'll see the issues anyway and tagging me messes with notification priorities.
Ha, I know exactly what we've done here, and funnily enough I looked at the line of code responsible, thought about changing it and thought "nah, that's right". I can fix this no worries.

Resolving patch:
diff --git a/qiskit/transpiler/passes/routing/stochastic_swap.py b/qiskit/transpiler/passes/routing/stochastic_swap.py
--- 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.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 @@ def _controlflow_layer_update(self, dagcircuit_output, layer_dag, current_layout
         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 @@ def _recursive_pass(self, initial_layout):
             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


Test patch:
diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py
--- a/test/python/compiler/test_transpiler.py
+++ b/test/python/compiler/test_transpiler.py
@@ -27,7 +27,7 @@
 
 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.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 @@ def test_transpile_with_custom_control_flow_target(self, opt_level):
         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 @@ def _visit_block(circuit, qubit_mapping=None):
         )
 
 
+@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
--- a/test/python/transpiler/test_stochastic_swap.py
+++ b/test/python/transpiler/test_stochastic_swap.py
@@ -591,11 +591,11 @@ def test_pre_if_else_route(self):
         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 @@ def test_pre_if_else_route(self):
         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 @@ def test_pre_if_else_route_post_x(self):
         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 @@ def test_pre_if_else_route_post_x(self):
         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 @@ def test_post_if_else_route(self):
         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 @@ def test_post_if_else_route(self):
         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 @@ def test_pre_if_else2(self):
         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 @@ def test_pre_if_else2(self):
         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 @@ def test_intra_if_else_route(self):
         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 @@ def test_intra_if_else_route(self):
         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 @@ def test_pre_intra_if_else(self):
         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 @@ def test_pre_intra_if_else(self):
         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 @@ def test_pre_intra_if_else(self):
         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 @@ def test_pre_intra_post_if_else(self):
         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 @@ def test_pre_intra_post_if_else(self):
         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 @@ def test_no_layout_change(self):
         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 @@ def test_no_layout_change(self):
         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 @@ def test_for_loop(self, nloops):
         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 @@ def test_for_loop(self, nloops):
         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 @@ def test_while_loop(self):
         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 @@ def test_nested_inner_cnot(self):
         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 @@ def test_nested_inner_cnot(self):
         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 @@ def test_nested_outer_cnot(self):
         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 @@ def test_nested_outer_cnot(self):
         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 @@ def test_disjoint_multiblock(self):
         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 @@ def _visit_block(circuit, qubit_mapping=None):
                         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)