Repository: Qiskit/qiskit

Issue:
QASM2 exporter: barriers with empty list of qubits silently accepted
### Environment

- **Qiskit Terra version**: 0.43.1 meta package, terra 0.24.1
- **Python version**: 3.10
- **Operating system**: docker continuumio/miniconda3


### What is happening?

When I append barriers with empty list of target qubits I get no warnings, but then the generated qasm is invalid.

### How can we reproduce the issue?

Run this python script:

```python
from qiskit import QuantumCircuit
qc = QuantumCircuit(4,4)
for q_index in range(0, 11, 4):
    # DEBUG ONLY
    print(f"q_index: {q_index}")
    print(f"qc.qubits[q_index:q_index+4]: {qc.qubits[q_index:q_index+4]}")
    # PROBLEMATIC CODE
    qc.barrier(qc.qubits[q_index:q_index+4])
print(qc.draw())

qc.qasm(filename="my.qasm")

QuantumCircuit.from_qasm_file("my.qasm").draw(output='mpl')
```
Produces this error:
```bash
q_index: 0
qc.qubits[q_index:q_index+4]: [Qubit(QuantumRegister(4, 'q'), 0), Qubit(QuantumRegister(4, 'q'), 1), Qubit(QuantumRegister(4, 'q'), 2), Qubit(QuantumRegister(4, 'q'), 3)]
q_index: 4
qc.qubits[q_index:q_index+4]: []
q_index: 8
qc.qubits[q_index:q_index+4]: []
      ░
q_0: ─░─
      ░
q_1: ─░─
      ░
q_2: ─░─
      ░
q_3: ─░─
      ░
c: 4/═══

Error near line 6 Column 32
...
  File ".../lib/python3.10/site-pack
ages/qiskit/qasm/qasmparser.py", line 397, in p_id_e                           raise QasmError("Expected an ID, received '" + str(program[1].value) +
"'")                                                                       qiskit.qasm.exceptions.QasmError: "Expected an ID, received ';'"
```
The error happens only when importing the qasm file, whereas I believe the mistake is done by the exporter, which generates the `barrier;` statement, see below.

This is the genrated QASM:
```qasm
OPENQASM 2.0;
include "qelib1.inc";
qreg q[4];
creg c[4];
barrier q[0],q[1],q[2],q[3];
barrier;
barrier;

```

### What should happen?

I would have expected the QASM exporter to generate a valid qasm, ready to be reimported.


### Any suggestions?

I would suggest to make the addition of barrier with empty lists raise a warning to the developer, because the problem happens also with `qc.barrier([])`, and the qiskit is silently generating invalid qasm.


Discussion:

Resolving patch:
diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py
--- a/qiskit/circuit/quantumcircuit.py
+++ b/qiskit/circuit/quantumcircuit.py
@@ -1716,6 +1716,10 @@ def qasm(
             elif operation.name == "reset":
                 instruction_qasm = f"reset {bit_labels[instruction.qubits[0]]};"
             elif operation.name == "barrier":
+                if not instruction.qubits:
+                    # Barriers with no operands are invalid in (strict) OQ2, and the statement
+                    # would have no meaning anyway.
+                    continue
                 qargs = ",".join(bit_labels[q] for q in instruction.qubits)
                 instruction_qasm = "barrier;" if not qargs else f"barrier {qargs};"
             else:


Test patch:
diff --git a/test/python/circuit/test_circuit_qasm.py b/test/python/circuit/test_circuit_qasm.py
--- a/test/python/circuit/test_circuit_qasm.py
+++ b/test/python/circuit/test_circuit_qasm.py
@@ -805,6 +805,23 @@ def test_sequencial_inner_gates_with_same_name(self):
 
         self.assertEqual(qc.qasm(), expected_output)
 
+    def test_empty_barrier(self):
+        """Test that a blank barrier statement in _Qiskit_ acts over all qubits, while an explicitly
+        no-op barrier (assuming Qiskit continues to allow this) is not output to OQ2 at all, since
+        the statement requires an argument in the spec."""
+        qc = QuantumCircuit(QuantumRegister(2, "qr1"), QuantumRegister(3, "qr2"))
+        qc.barrier()  # In Qiskit land, this affects _all_ qubits.
+        qc.barrier([])  # This explicitly affects _no_ qubits (so is totally meaningless).
+
+        expected = """\
+OPENQASM 2.0;
+include "qelib1.inc";
+qreg qr1[2];
+qreg qr2[3];
+barrier qr1[0],qr1[1],qr2[0],qr2[1],qr2[2];
+"""
+        self.assertEqual(qc.qasm(), expected)
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/test/python/qasm2/test_parse_errors.py b/test/python/qasm2/test_parse_errors.py
--- a/test/python/qasm2/test_parse_errors.py
+++ b/test/python/qasm2/test_parse_errors.py
@@ -865,3 +865,10 @@ def test_required_version_empty(self):
             qiskit.qasm2.QASM2ParseError, r"\[strict\] .*needed a version statement"
         ):
             qiskit.qasm2.loads("", strict=True)
+
+    def test_barrier_requires_args(self):
+        program = "OPENQASM 2.0; qreg q[2]; barrier;"
+        with self.assertRaisesRegex(
+            qiskit.qasm2.QASM2ParseError, r"\[strict\] barrier statements must have at least one"
+        ):
+            qiskit.qasm2.loads(program, strict=True)