Skip to content
This repository was archived by the owner on Oct 11, 2025. It is now read-only.

Commit fb84e3a

Browse files
[mlir][TableGen] Emit interface traits after all interfaces (#147699)
Interface traits may provide default implementation of methods. When this happens, the implementation may rely on another interface that is not yet defined meaning that one gets "incomplete type" error during C++ compilation. In pseudo-code, the problem is the following: ``` InterfaceA has methodB() { return InterfaceB(); } InterfaceB defined later // What's generated is: class InterfaceA { ... } class InterfaceATrait { // error: InterfaceB is an incomplete type InterfaceB methodB() { return InterfaceB(); } } class InterfaceB { ... } // defined here ``` The two more "advanced" cases are: * Cyclic dependency (A requires B and B requires A) * Type-traited usage of an incomplete type (e.g. `FailureOr<InterfaceB>`) It seems reasonable to emit interface traits *after* all of the interfaces have been defined to avoid the problem altogether. As a drive by, make forward declarations of the interfaces early so that user code does not need to forward declare.
1 parent 27026fe commit fb84e3a

File tree

1 file changed

+42
-10
lines changed

1 file changed

+42
-10
lines changed

mlir/tools/mlir-tblgen/OpInterfacesGen.cpp

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,9 @@ class InterfaceGenerator {
9696
void emitConceptDecl(const Interface &interface);
9797
void emitModelDecl(const Interface &interface);
9898
void emitModelMethodsDef(const Interface &interface);
99-
void emitTraitDecl(const Interface &interface, StringRef interfaceName,
100-
StringRef interfaceTraitsName);
99+
void forwardDeclareInterface(const Interface &interface);
101100
void emitInterfaceDecl(const Interface &interface);
101+
void emitInterfaceTraitDecl(const Interface &interface);
102102

103103
/// The set of interface records to emit.
104104
std::vector<const Record *> defs;
@@ -445,9 +445,16 @@ void InterfaceGenerator::emitModelMethodsDef(const Interface &interface) {
445445
os << "} // namespace " << ns << "\n";
446446
}
447447

448-
void InterfaceGenerator::emitTraitDecl(const Interface &interface,
449-
StringRef interfaceName,
450-
StringRef interfaceTraitsName) {
448+
void InterfaceGenerator::emitInterfaceTraitDecl(const Interface &interface) {
449+
llvm::SmallVector<StringRef, 2> namespaces;
450+
llvm::SplitString(interface.getCppNamespace(), namespaces, "::");
451+
for (StringRef ns : namespaces)
452+
os << "namespace " << ns << " {\n";
453+
454+
os << "namespace detail {\n";
455+
456+
StringRef interfaceName = interface.getName();
457+
auto interfaceTraitsName = (interfaceName + "InterfaceTraits").str();
451458
os << llvm::formatv(" template <typename {3}>\n"
452459
" struct {0}Trait : public ::mlir::{2}<{0},"
453460
" detail::{1}>::Trait<{3}> {{\n",
@@ -494,6 +501,10 @@ void InterfaceGenerator::emitTraitDecl(const Interface &interface,
494501
os << tblgen::tgfmt(*extraTraitDecls, &traitMethodFmt) << "\n";
495502

496503
os << " };\n";
504+
os << "}// namespace detail\n";
505+
506+
for (StringRef ns : llvm::reverse(namespaces))
507+
os << "} // namespace " << ns << "\n";
497508
}
498509

499510
static void emitInterfaceDeclMethods(const Interface &interface,
@@ -517,6 +528,27 @@ static void emitInterfaceDeclMethods(const Interface &interface,
517528
os << tblgen::tgfmt(extraDecls->rtrim(), &extraDeclsFmt) << "\n";
518529
}
519530

531+
void InterfaceGenerator::forwardDeclareInterface(const Interface &interface) {
532+
llvm::SmallVector<StringRef, 2> namespaces;
533+
llvm::SplitString(interface.getCppNamespace(), namespaces, "::");
534+
for (StringRef ns : namespaces)
535+
os << "namespace " << ns << " {\n";
536+
537+
// Emit a forward declaration of the interface class so that it becomes usable
538+
// in the signature of its methods.
539+
std::string comments = tblgen::emitSummaryAndDescComments(
540+
"", interface.getDescription().value_or(""));
541+
if (!comments.empty()) {
542+
os << comments << "\n";
543+
}
544+
545+
StringRef interfaceName = interface.getName();
546+
os << "class " << interfaceName << ";\n";
547+
548+
for (StringRef ns : llvm::reverse(namespaces))
549+
os << "} // namespace " << ns << "\n";
550+
}
551+
520552
void InterfaceGenerator::emitInterfaceDecl(const Interface &interface) {
521553
llvm::SmallVector<StringRef, 2> namespaces;
522554
llvm::SplitString(interface.getCppNamespace(), namespaces, "::");
@@ -533,7 +565,6 @@ void InterfaceGenerator::emitInterfaceDecl(const Interface &interface) {
533565
if (!comments.empty()) {
534566
os << comments << "\n";
535567
}
536-
os << "class " << interfaceName << ";\n";
537568

538569
// Emit the traits struct containing the concept and model declarations.
539570
os << "namespace detail {\n"
@@ -603,10 +634,6 @@ void InterfaceGenerator::emitInterfaceDecl(const Interface &interface) {
603634

604635
os << "};\n";
605636

606-
os << "namespace detail {\n";
607-
emitTraitDecl(interface, interfaceName, interfaceTraitsName);
608-
os << "}// namespace detail\n";
609-
610637
for (StringRef ns : llvm::reverse(namespaces))
611638
os << "} // namespace " << ns << "\n";
612639
}
@@ -619,10 +646,15 @@ bool InterfaceGenerator::emitInterfaceDecls() {
619646
llvm::sort(sortedDefs, [](const Record *lhs, const Record *rhs) {
620647
return lhs->getID() < rhs->getID();
621648
});
649+
for (const Record *def : sortedDefs)
650+
forwardDeclareInterface(Interface(def));
622651
for (const Record *def : sortedDefs)
623652
emitInterfaceDecl(Interface(def));
653+
for (const Record *def : sortedDefs)
654+
emitInterfaceTraitDecl(Interface(def));
624655
for (const Record *def : sortedDefs)
625656
emitModelMethodsDef(Interface(def));
657+
626658
return false;
627659
}
628660

0 commit comments

Comments
 (0)