[Mlir-commits] [mlir] [mlir] Fix assertion crash in test-symbol-uses with nested modules (PR #185069)

Mehdi Amini llvmlistbot at llvm.org
Fri Mar 6 09:57:11 PST 2026


https://github.com/joker-eph created https://github.com/llvm/llvm-project/pull/185069

The `SymbolUsesPass` walked all nested `SymbolOpInterface` ops in a module, including those belonging to nested symbol tables (e.g., nested modules). When an external `func.func` inside a nested module had no uses in the outer module's body region, it was incorrectly added to `deadFunctions` for erasure. Since the outer module's `SymbolTable` does not contain the inner module's symbols, the subsequent `table.lookup(name)` assertion would fail with:

  Assertion `table.lookup(name) && "expected no unknown operations"` failed.

Fix by only tracking functions that are direct children of the enclosing module, skipping functions owned by nested symbol tables.

Fixes #60583

Assisted-by: Claude Code

>From 2bd18036e622a18df9a5beafd8949eff4b0b53cd Mon Sep 17 00:00:00 2001
From: Mehdi Amini <joker.eph at gmail.com>
Date: Thu, 5 Mar 2026 08:23:52 -0800
Subject: [PATCH] [mlir] Fix assertion crash in test-symbol-uses with nested
 modules

The `SymbolUsesPass` walked all nested `SymbolOpInterface` ops in a
module, including those belonging to nested symbol tables (e.g., nested
modules). When an external `func.func` inside a nested module had no
uses in the outer module's body region, it was incorrectly added to
`deadFunctions` for erasure. Since the outer module's `SymbolTable`
does not contain the inner module's symbols, the subsequent
`table.lookup(name)` assertion would fail with:

  Assertion `table.lookup(name) && "expected no unknown operations"` failed.

Fix by only tracking functions that are direct children of the enclosing
module, skipping functions owned by nested symbol tables.

Fixes #60583

Assisted-by: Claude Code
---
 mlir/test/IR/test-symbol-uses.mlir  | 12 ++++++++++++
 mlir/test/lib/IR/TestSymbolUses.cpp |  7 ++++++-
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/mlir/test/IR/test-symbol-uses.mlir b/mlir/test/IR/test-symbol-uses.mlir
index d9d839e9fc307..eb0c5c379bb31 100644
--- a/mlir/test/IR/test-symbol-uses.mlir
+++ b/mlir/test/IR/test-symbol-uses.mlir
@@ -93,3 +93,15 @@ module {
     return
   }
 }
+
+// -----
+
+// Test that external functions in nested modules are not incorrectly erased
+// from the outer module's symbol table.
+// Regression test for https://github.com/llvm/llvm-project/issues/60583
+module {
+  module {
+    // expected-remark at below {{symbol has no uses}}
+    func.func private @printMemrefF32(%ptr : memref<*xf32>)
+  }
+}
diff --git a/mlir/test/lib/IR/TestSymbolUses.cpp b/mlir/test/lib/IR/TestSymbolUses.cpp
index 24f7d8505bebd..6aac9bfc8baa4 100644
--- a/mlir/test/lib/IR/TestSymbolUses.cpp
+++ b/mlir/test/lib/IR/TestSymbolUses.cpp
@@ -43,7 +43,12 @@ struct SymbolUsesPass
     // Test the functionality of symbolKnownUseEmpty.
     if (SymbolTable::symbolKnownUseEmpty(symbol, &module.getBodyRegion())) {
       func::FuncOp funcSymbol = dyn_cast<func::FuncOp>(symbol.getOperation());
-      if (funcSymbol && funcSymbol.isExternal())
+      // Only track functions that are direct children of the enclosing module.
+      // Functions in nested symbol tables (e.g., nested modules) belong to a
+      // different symbol table and cannot be erased via the outer module's
+      // SymbolTable instance.
+      if (funcSymbol && funcSymbol.isExternal() &&
+          funcSymbol->getParentOp() == module.getOperation())
         deadFunctions.push_back(funcSymbol);
 
       symbol->emitRemark() << "symbol has no uses";



More information about the Mlir-commits mailing list