Repository: Qiskit/qiskit

Issue:
Conditional Measurement is not conditional when exported to OpenQASM 3
### Environment

- **Qiskit Terra version**: main 
- **Python version**: 3.9
- **Operating system**:  OSX


### What is happening?

When exporting a circuit with a conditional measurement to OpenQASM 3 the measurement is not conditional.

### How can we reproduce the issue?

```
cr = ClassicalRegister(3)
qr = QuantumRegister(3)
qc = QuantumCircuit(qr, cr)

# Prepare |011>
qc.x(qr[:2])
# Measure "001"
qc.measure(qr[0], cr[0])
# Conditionally measure "011", but the second bit is not reported
# due to conditional measurement phase 1 limitations. The measurement
# value is still available for runtime conditional executions.
qc.measure(qr[1], cr[1]).c_if(cr[0], 1)
# Conditionally prepare |111> based on the conditional measurement result
qc.x(qr[2]).c_if(cr[1], 1)
# Perform a final un-conditional measurement who's value will be determined
# by the previous conditional measurement which is due to the usage of the gate
# conditioned on the measurement result.
qc.measure(qr[2], cr[2])
```

Gives

```
OPENQASM 3;
bit[3] c0;
x $3;
x $4;
c0[0] = measure $3;
c0[1] = measure $4;
if (c0[1] == 1) {
  x $5;
}
c0[2] = measure $5;
```

### What should happen?

Should give

```
OPENQASM 3;
bit[3] c0;
x $3;
x $4;
c0[0] = measure $3;

if (c0[1] == 1) {
   c0[1] = measure $4;
}
if (c0[1] == 1) {
  x $5;
}
c0[2] = measure $5;

### Any suggestions?

_No response_


Discussion:

Resolving patch:
diff --git a/qiskit/qasm3/exporter.py b/qiskit/qasm3/exporter.py
--- a/qiskit/qasm3/exporter.py
+++ b/qiskit/qasm3/exporter.py
@@ -779,45 +779,49 @@ def build_quantum_instructions(self, instructions):
         """Builds a list of call statements"""
         ret = []
         for instruction in instructions:
+            if isinstance(instruction.operation, ForLoopOp):
+                ret.append(self.build_for_loop(instruction))
+                continue
+            if isinstance(instruction.operation, WhileLoopOp):
+                ret.append(self.build_while_loop(instruction))
+                continue
+            if isinstance(instruction.operation, IfElseOp):
+                ret.append(self.build_if_statement(instruction))
+                continue
+            # Build the node, ignoring any condition.
             if isinstance(instruction.operation, Gate):
-                if instruction.operation.condition:
-                    eqcondition = self.build_eqcondition(instruction.operation.condition)
-                    operation_without_condition = instruction.operation.copy()
-                    operation_without_condition.condition = None
-                    true_body = self.build_program_block(
-                        [instruction.replace(operation=operation_without_condition)]
-                    )
-                    ret.append(ast.BranchingStatement(eqcondition, true_body))
-                else:
-                    ret.append(self.build_gate_call(instruction))
+                nodes = [self.build_gate_call(instruction)]
             elif isinstance(instruction.operation, Barrier):
                 operands = [
                     self.build_single_bit_reference(operand) for operand in instruction.qubits
                 ]
-                ret.append(ast.QuantumBarrier(operands))
+                nodes = [ast.QuantumBarrier(operands)]
             elif isinstance(instruction.operation, Measure):
                 measurement = ast.QuantumMeasurement(
                     [self.build_single_bit_reference(operand) for operand in instruction.qubits]
                 )
                 qubit = self.build_single_bit_reference(instruction.clbits[0])
-                ret.append(ast.QuantumMeasurementAssignment(qubit, measurement))
+                nodes = [ast.QuantumMeasurementAssignment(qubit, measurement)]
             elif isinstance(instruction.operation, Reset):
-                for operand in instruction.qubits:
-                    ret.append(ast.QuantumReset(self.build_single_bit_reference(operand)))
+                nodes = [
+                    ast.QuantumReset(self.build_single_bit_reference(operand))
+                    for operand in instruction.qubits
+                ]
             elif isinstance(instruction.operation, Delay):
-                ret.append(self.build_delay(instruction))
-            elif isinstance(instruction.operation, ForLoopOp):
-                ret.append(self.build_for_loop(instruction))
-            elif isinstance(instruction.operation, WhileLoopOp):
-                ret.append(self.build_while_loop(instruction))
-            elif isinstance(instruction.operation, IfElseOp):
-                ret.append(self.build_if_statement(instruction))
+                nodes = [self.build_delay(instruction)]
             elif isinstance(instruction.operation, BreakLoopOp):
-                ret.append(ast.BreakStatement())
+                nodes = [ast.BreakStatement()]
             elif isinstance(instruction.operation, ContinueLoopOp):
-                ret.append(ast.ContinueStatement())
+                nodes = [ast.ContinueStatement()]
+            else:
+                nodes = [self.build_subroutine_call(instruction)]
+
+            if instruction.operation.condition is None:
+                ret.extend(nodes)
             else:
-                ret.append(self.build_subroutine_call(instruction))
+                eqcondition = self.build_eqcondition(instruction.operation.condition)
+                body = ast.ProgramBlock(nodes)
+                ret.append(ast.BranchingStatement(eqcondition, body))
         return ret
 
     def build_if_statement(self, instruction: CircuitInstruction) -> ast.BranchingStatement:


Test patch:
diff --git a/test/python/circuit/test_circuit_qasm3.py b/test/python/circuit/test_circuit_qasm3.py
--- a/test/python/circuit/test_circuit_qasm3.py
+++ b/test/python/circuit/test_circuit_qasm3.py
@@ -22,7 +22,7 @@
 from ddt import ddt, data
 
 from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit, transpile
-from qiskit.circuit import Parameter, Qubit, Clbit, Instruction, Gate
+from qiskit.circuit import Parameter, Qubit, Clbit, Instruction, Gate, Delay, Barrier
 from qiskit.test import QiskitTestCase
 from qiskit.qasm3 import Exporter, dumps, dump, QASM3ExporterError
 from qiskit.qasm3.exporter import QASM3Builder
@@ -1696,6 +1696,60 @@ def test_no_include(self):
         )
         self.assertEqual(Exporter(includes=[]).dumps(circuit), expected_qasm)
 
+    def test_unusual_conditions(self):
+        """Test that special QASM constructs such as ``measure`` are correctly handled when the
+        Terra instructions have old-style conditions."""
+        qc = QuantumCircuit(3, 2)
+        qc.h(0)
+        qc.measure(0, 0)
+        qc.measure(1, 1).c_if(0, True)
+        qc.reset([0, 1]).c_if(0, True)
+        with qc.while_loop((qc.clbits[0], True)):
+            qc.break_loop().c_if(0, True)
+            qc.continue_loop().c_if(0, True)
+        # Terra forbids delay and barrier from being conditioned through `c_if`, but in theory they
+        # should work fine in a dynamic-circuits sense (although what a conditional barrier _means_
+        # is a whole other kettle of fish).
+        delay = Delay(16, "dt")
+        delay.condition = (qc.clbits[0], True)
+        qc.append(delay, [0], [])
+        barrier = Barrier(2)
+        barrier.condition = (qc.clbits[0], True)
+        qc.append(barrier, [0, 1], [])
+
+        expected = """
+OPENQASM 3;
+include "stdgates.inc";
+bit[2] c;
+qubit[3] _all_qubits;
+let q = _all_qubits[0:2];
+h q[0];
+c[0] = measure q[0];
+if (c[0] == 1) {
+  c[1] = measure q[1];
+}
+if (c[0] == 1) {
+  reset q[0];
+}
+if (c[0] == 1) {
+  reset q[1];
+}
+while (c[0] == 1) {
+  if (c[0] == 1) {
+    break;
+  }
+  if (c[0] == 1) {
+    continue;
+  }
+}
+if (c[0] == 1) {
+  delay[16dt] q[0];
+}
+if (c[0] == 1) {
+  barrier q[0], q[1];
+}"""
+        self.assertEqual(dumps(qc).strip(), expected.strip())
+
 
 @ddt
 class TestQASM3ExporterFailurePaths(QiskitTestCase):