[Mlir-commits] [mlir] [mlir][tblgen] Error on unsubstituted $_self in op trait predicates (PR #227263)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Sat Oct 31 03:47:11 PDT 2026
https://github.com/LiRvs-Miria updated https://github.com/llvm/llvm-project/pull/227263
>From 1966f5091fbe7ee326c367c6ace9692e09779898 Mon Sep 17 00:00:00 2001
From: LiRvs-Miria <1753531985 at qq.com>
Date: Tue, 29 Sep 2026 18:22:59 +0800
Subject: [PATCH] [mlir][tblgen] Error on unsubstituted $_self in op trait
predicates
PredOpTrait predicates are expanded against the whole operation, so
$_self is not bound in that context. If an ODS definition uses $_self
in a trait predicate, tblgen silently emits C++ containing
$_self<no-subst-found>, which later fails to compile with a confusing
error pointing into the generated .inc file.
Detect the unsubstituted placeholder while formatting the predicate and
report a fatal error at the ODS definition site instead, naming the
operation and the trait, and pointing to the two remedies: use $_op to
refer to the operation, or pre-substitute $_self with !subst as the
AllTypesMatch / TypesMatchWith primitives do.
A new ERROR18 case in op-error.td covers the diagnostic; the check runs
while generating the op definitions (-gen-op-defs).
---
mlir/test/mlir-tblgen/op-error.td | 14 ++++++++++++++
mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp | 14 ++++++++++++--
2 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/mlir/test/mlir-tblgen/op-error.td b/mlir/test/mlir-tblgen/op-error.td
index ec90891034fbe..1337e793dd15a 100644
--- a/mlir/test/mlir-tblgen/op-error.td
+++ b/mlir/test/mlir-tblgen/op-error.td
@@ -15,6 +15,8 @@
// RUN: not mlir-tblgen -gen-op-decls -I %S/../../include -DERROR15 %s 2>&1 | FileCheck --check-prefix=ERROR15 %s
// RUN: not mlir-tblgen -gen-op-decls -I %S/../../include -DERROR16 %s 2>&1 | FileCheck --check-prefix=ERROR16 %s
// RUN: not mlir-tblgen -gen-op-decls -I %S/../../include -DERROR17 %s 2>&1 | FileCheck --check-prefix=ERROR17 %s
+// This error is caught while generating the op verifier.
+// RUN: not mlir-tblgen -gen-op-defs -I %S/../../include -DERROR18 %s 2>&1 | FileCheck --check-prefix=ERROR18 %s
include "mlir/IR/OpBase.td"
@@ -166,3 +168,15 @@ def OpWithLegacyResultSegmentProperty
let results = (outs Variadic<AnyType>:$lhs, Variadic<AnyType>:$rhs);
}
#endif
+
+#ifdef ERROR18
+// ERROR18: error: trait 'lhs and rhs must have the same type' on operation 'test_dialect.unsubstituted_self' uses $_self in its predicate, but $_self is not bound in trait context
+def UnsubstitutedSelfOp
+ : Op<Test_Dialect, "unsubstituted_self",
+ [PredOpTrait<"lhs and rhs must have the same type",
+ CPred<"$_self.getType() == $_op.getOperand(0).getType()">
+ >
+ ]> {
+ let arguments = (ins AnyType:$a, AnyType:$b);
+}
+#endif
diff --git a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
index 62d057af2132b..c7f007b8fc021 100644
--- a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
+++ b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp
@@ -3776,10 +3776,20 @@ void OpEmitter::genVerifier() {
for (auto &trait : op.getTraits()) {
if (auto *t = dyn_cast<tblgen::PredTrait>(&trait)) {
+ // Trait predicates expand against the whole operation, so $_self is not
+ // substituted here; catch it and report at the ODS level instead
+ std::string pred = tgfmt(t->getPredTemplate(), &verifyCtx);
+ if (StringRef(pred).contains("<no-subst-found>"))
+ PrintFatalError(op.getLoc(),
+ "trait '" + t->getSummary() + "' on operation '" +
+ op.getOperationName() +
+ "' uses $_self in its predicate, but $_self is "
+ "not bound in trait context; use $_op to refer "
+ "to the operation, or pre-substitute $_self with "
+ "!subst");
implBody << tgfmt(" if (!($0))\n "
"return emitOpError(\"failed to verify that $1\");\n",
- &verifyCtx, tgfmt(t->getPredTemplate(), &verifyCtx),
- t->getSummary());
+ &verifyCtx, pred, t->getSummary());
}
}
More information about the Mlir-commits
mailing list