| # RUN: %PYTHON %s | |
| # It is sufficient that this doesn't assert. | |
| from mlir.ir import * | |
| def createDetachedModule(): | |
| module = Module.create() | |
| with InsertionPoint(module.body): | |
| # TODO: Python bindings are currently unaware that modules are also | |
| # operations, so having a module erased won't trigger the cascading | |
| # removal of live operations (#93337). Use a non-module operation | |
| # instead. | |
| nested = Operation.create("test.some_operation", regions=1) | |
| # When the operation is detached from parent, it is considered to be | |
| # owned by Python. It will therefore be erased when the Python object | |
| # is destroyed. | |
| nested.detach_from_parent() | |
| # However, we create and maintain references to operations within | |
| # `nested`. These references keep the corresponding operations in the | |
| # "live" list even if they have been erased in C++, making them | |
| # "zombie". If the C++ allocator reuses one of the address previously | |
| # used for a now-"zombie" operation, this used to result in an | |
| # assertion "cannot create detached operation that already exists" from | |
| # the bindings code. Erasing the detached operation should result in | |
| # removing all nested operations from the live list. | |
| # | |
| # Note that the assertion is not guaranteed since it depends on the | |
| # behavior of the allocator on the C++ side, so this test mail fail | |
| # intermittently. | |
| with InsertionPoint(nested.regions[0].blocks.append()): | |
| a = [Operation.create("test.some_other_operation") for i in range(100)] | |
| return a | |
| def createManyDetachedModules(): | |
| with Context() as ctx, Location.unknown(): | |
| ctx.allow_unregistered_dialects = True | |
| for j in range(100): | |
| a = createDetachedModule() | |
| if __name__ == "__main__": | |
| createManyDetachedModules() |