Skip to content

[python] Early return statements in kernels are silently ignored, producing wrong circuits #4845

Description

@wsttiger

Required prerequisites

  • Consult the security policy. If reporting a security vulnerability, do not report the bug using this form. Use the process described in the policy to report the issue.
  • Make sure you've read the documentation. Your issue may be addressed there.
  • Search the issue tracker to verify that this hasn't already been reported. +1 or comment there if it has.

Describe the bug

An if condition: return guard inside a @cudaq.kernel compiles without
warning but has no effect: the operations after it execute regardless of
the condition. This produces silently wrong circuits rather than an
error.

It is easy to miss in testing: guards whose guarded code consists of loops
over zero-trip ranges appear to work (the loops do nothing for exactly the
inputs the guard was for), so a kernel can carry dead guards through an
entire test suite. We found it porting a C++ device kernel whose
if steps == 0: return was masked by for _ in range(steps), while its
unsupported-order guard executed a wrong product formula instead of the
documented no-op.

(Related but distinct: #1657 is about return None with a declared return
type; this issue is bare return control flow in void kernels being
dropped.)

Steps to reproduce the bug

import cudaq
cudaq.set_target("qpp-cpu")

@cudaq.kernel
def guarded(skip: int):
    q = cudaq.qvector(1)
    if skip == 1:
        return
    x(q[0])

print(cudaq.sample(guarded, 0))  # { 1:1000 }  (expected)
print(cudaq.sample(guarded, 1))  # { 1:1000 }  (expected { 0:1000 })

Also reproduces with multi-clause conditions
(if a != 1 and a != 2: return) and with multiple sequential guards.

Expected behavior

Either honor return control flow in void kernels, or — if early return
is intentionally unsupported — reject it with a compile error. Silent
acceptance is the worst of both: the common C++ device-kernel idiom
"invalid runtime inputs are no-ops via early return" ports over as a
silently wrong circuit.

Is this a regression? If it is, put the last known working version (or commit) here.

Not a regression

Environment

  • CUDA-Q built from source at commit 0be565550f4c23affdcbed9e4eaec38d2d0915e6
  • Python 3.11.x, target qpp-cpu (library mode)
  • AlmaLinux 8.10, x86_64

All reproducers below were executed and verified against this build.

Suggestions

Workaround we use: restructure kernel bodies as a single positively-guarded
if-block (valid = ... then if valid: <entire body>).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions