[mlir][Parser] Fix crash when resolving invalid operands with missing location (#128163)

When `resolveOperands` reports an error and no valid `SMLoc` was
provided, report the error at the beginning of the op instead of
crashing.

```
Assert `Ptr >= BufStart && Ptr <= Buffer->getBufferEnd()' in llvm/lib/Support/SourceMgr.cpp:llvm::SourceMgr::SrcBuffer::getLineNumberSpecialized failed
```

E.g., this is currently the case when parsing the following op with a
type but without any operands:
```
let assemblyFormat = "$str (`,` $args^)? attr-dict (`:` type($args)^)?";
```

Reported error (with this PR):
```
within split at mlir/test/IR/invalid-ops.mlir:122 offset :4:1: error: custom op 'test.variadic_args_types_split' number of operands and types do not match: got 0 operands and 1 types
test.variadic_args_types_split "hello_world" : i32
^
```

In the ODS-generated C++, the `SMLoc` is populated when parsing the
optional group containing `$args`. However, this group is missing in the
test case.

There are likely additional hand-written parsers that suffer from the
same problem.

Note: I tried emitting a second `SMLoc` for the optional type group in
the `OpFormatGen.cpp`, but this adds quite a bit of complexity in the
code base for little improvement in user experience.
This commit is contained in:
Matthias Springer 2025-02-21 12:33:38 +01:00 committed by GitHub
parent 25e12726f7
commit 8a3222d8da
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 14 additions and 2 deletions

View File

@ -1603,10 +1603,12 @@ public:
SmallVectorImpl<Value> &result) {
size_t operandSize = llvm::range_size(operands);
size_t typeSize = llvm::range_size(types);
if (operandSize != typeSize)
return emitError(loc)
if (operandSize != typeSize) {
// If no location was provided, report errors at the beginning of the op.
return emitError(loc.isValid() ? loc : getNameLoc())
<< "number of operands and types do not match: got " << operandSize
<< " operands and " << typeSize << " types";
}
for (auto [operand, type] : llvm::zip_equal(operands, types))
if (resolveOperand(operand, type, result))

View File

@ -118,3 +118,8 @@ func.func @invalid_splat(%v : f32) { // expected-note {{prior use here}}
// expected-error@+1 {{expected ':' after block name}}
"g"()({^a:^b })
// -----
// expected-error@+1 {{number of operands and types do not match: got 0 operands and 1 types}}
test.variadic_args_types_split "hello_world" : i32

View File

@ -767,4 +767,9 @@ def FormatInferTypeVariadicOperandsOp
}];
}
def VariadicArgsTypesSplit : TEST_Op<"variadic_args_types_split"> {
let arguments = (ins StrAttr:$str, Variadic<AnyType>:$args);
let assemblyFormat = "$str (`,` $args^)? attr-dict (`:` type($args)^)?";
}
#endif // TEST_OPS_SYNTAX