Skip to content

Commit 8b7e669

Browse files
committed
[mlir][AsmFormat] Avoid invalidating the iterator when verifying attributes
Summary: 'it' may get invalidated when recursing into optional groups. This revision refactors the inner loop to avoid the need to compare the iterator after invalidation. Differential Revision: https://reviews.llvm.org/D77686
1 parent 6011627 commit 8b7e669

File tree

1 file changed

+58
-44
lines changed

1 file changed

+58
-44
lines changed

mlir/tools/mlir-tblgen/OpFormatGen.cpp

Lines changed: 58 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,8 +1255,16 @@ class FormatParser {
12551255
Optional<StringRef> transformer;
12561256
};
12571257

1258+
/// An iterator over the elements of a format group.
1259+
using ElementsIterT = llvm::pointee_iterator<
1260+
std::vector<std::unique_ptr<Element>>::const_iterator>;
1261+
12581262
/// Verify the state of operation attributes within the format.
12591263
LogicalResult verifyAttributes(llvm::SMLoc loc);
1264+
/// Verify the attribute elements at the back of the given stack of iterators.
1265+
LogicalResult verifyAttributes(
1266+
llvm::SMLoc loc,
1267+
SmallVectorImpl<std::pair<ElementsIterT, ElementsIterT>> &iteratorStack);
12601268

12611269
/// Verify the state of operation operands within the format.
12621270
LogicalResult
@@ -1423,54 +1431,60 @@ LogicalResult FormatParser::verifyAttributes(llvm::SMLoc loc) {
14231431
std::vector<std::unique_ptr<Element>>::const_iterator>;
14241432
SmallVector<std::pair<ElementsIterT, ElementsIterT>, 1> iteratorStack;
14251433
iteratorStack.emplace_back(fmt.elements.begin(), fmt.elements.end());
1426-
while (!iteratorStack.empty()) {
1427-
auto &stackIt = iteratorStack.back();
1428-
ElementsIterT &it = stackIt.first, e = stackIt.second;
1429-
while (it != e) {
1430-
Element *element = &*(it++);
1431-
1432-
// Traverse into optional groups.
1433-
if (auto *optional = dyn_cast<OptionalElement>(element)) {
1434-
auto elements = optional->getElements();
1435-
iteratorStack.emplace_back(elements.begin(), elements.end());
1436-
break;
1437-
}
1434+
while (!iteratorStack.empty())
1435+
if (failed(verifyAttributes(loc, iteratorStack)))
1436+
return failure();
1437+
return success();
1438+
}
1439+
/// Verify the attribute elements at the back of the given stack of iterators.
1440+
LogicalResult FormatParser::verifyAttributes(
1441+
llvm::SMLoc loc,
1442+
SmallVectorImpl<std::pair<ElementsIterT, ElementsIterT>> &iteratorStack) {
1443+
auto &stackIt = iteratorStack.back();
1444+
ElementsIterT &it = stackIt.first, e = stackIt.second;
1445+
while (it != e) {
1446+
Element *element = &*(it++);
1447+
1448+
// Traverse into optional groups.
1449+
if (auto *optional = dyn_cast<OptionalElement>(element)) {
1450+
auto elements = optional->getElements();
1451+
iteratorStack.emplace_back(elements.begin(), elements.end());
1452+
return success();
1453+
}
1454+
1455+
// We are checking for an attribute element followed by a `:`, so there is
1456+
// no need to check the end.
1457+
if (it == e && iteratorStack.size() == 1)
1458+
break;
1459+
1460+
// Check for an attribute with a constant type builder, followed by a `:`.
1461+
auto *prevAttr = dyn_cast<AttributeVariable>(element);
1462+
if (!prevAttr || prevAttr->getTypeBuilder())
1463+
continue;
14381464

1439-
// We are checking for an attribute element followed by a `:`, so there is
1440-
// no need to check the end.
1441-
if (it == e && iteratorStack.size() == 1)
1442-
break;
1443-
1444-
// Check for an attribute with a constant type builder, followed by a `:`.
1445-
auto *prevAttr = dyn_cast<AttributeVariable>(element);
1446-
if (!prevAttr || prevAttr->getTypeBuilder())
1447-
continue;
1448-
1449-
// Check the next iterator within the stack for literal elements.
1450-
for (auto &nextItPair : iteratorStack) {
1451-
ElementsIterT nextIt = nextItPair.first, nextE = nextItPair.second;
1452-
for (; nextIt != nextE; ++nextIt) {
1453-
// Skip any trailing optional groups or attribute dictionaries.
1454-
if (isa<AttrDictDirective>(*nextIt) || isa<OptionalElement>(*nextIt))
1455-
continue;
1456-
1457-
// We are only interested in `:` literals.
1458-
auto *literal = dyn_cast<LiteralElement>(&*nextIt);
1459-
if (!literal || literal->getLiteral() != ":")
1460-
break;
1461-
1462-
// TODO: Use the ___location of the literal element itself.
1463-
return emitError(
1464-
loc, llvm::formatv("format ambiguity caused by `:` literal found "
1465-
"after attribute `{0}` which does not have "
1466-
"a buildable type",
1467-
prevAttr->getVar()->name));
1468-
}
1465+
// Check the next iterator within the stack for literal elements.
1466+
for (auto &nextItPair : iteratorStack) {
1467+
ElementsIterT nextIt = nextItPair.first, nextE = nextItPair.second;
1468+
for (; nextIt != nextE; ++nextIt) {
1469+
// Skip any trailing optional groups or attribute dictionaries.
1470+
if (isa<AttrDictDirective>(*nextIt) || isa<OptionalElement>(*nextIt))
1471+
continue;
1472+
1473+
// We are only interested in `:` literals.
1474+
auto *literal = dyn_cast<LiteralElement>(&*nextIt);
1475+
if (!literal || literal->getLiteral() != ":")
1476+
break;
1477+
1478+
// TODO: Use the ___location of the literal element itself.
1479+
return emitError(
1480+
loc, llvm::formatv("format ambiguity caused by `:` literal found "
1481+
"after attribute `{0}` which does not have "
1482+
"a buildable type",
1483+
prevAttr->getVar()->name));
14691484
}
14701485
}
1471-
if (it == e)
1472-
iteratorStack.pop_back();
14731486
}
1487+
iteratorStack.pop_back();
14741488
return success();
14751489
}
14761490

0 commit comments

Comments
 (0)