[mlir] Fix leak in case of failed parse

A Block is optionally allocated & leaks in case of failed parse. Inline the
function and ensure Block gets freed unless parse is successful.

Differential Revision: https://reviews.llvm.org/D122112
This commit is contained in:
Jacques Pienaar 2022-03-28 20:04:31 -07:00
parent 2b3becb41d
commit 0217d1178b
2 changed files with 41 additions and 34 deletions

View File

@ -394,10 +394,6 @@ public:
/// us to diagnose references to blocks that are not defined precisely.
Block *getBlockNamed(StringRef name, SMLoc loc);
/// Define the block with the specified name. Returns the Block* or nullptr in
/// the case of redefinition.
Block *defineBlockNamed(StringRef name, SMLoc loc, Block *existing);
private:
/// This class represents a definition of a Block.
struct BlockDefinition {
@ -1953,11 +1949,38 @@ ParseResult OperationParser::parseBlock(Block *&block) {
if (parseToken(Token::caret_identifier, "expected block name"))
return failure();
block = defineBlockNamed(name, nameLoc, block);
// Define the block with the specified name.
auto &blockAndLoc = getBlockInfoByName(name);
blockAndLoc.loc = nameLoc;
// Fail if the block was already defined.
if (!block)
// Use a unique pointer for in-flight block being parsed. Release ownership
// only in the case of a successful parse. This ensures that the Block
// allocated is released if the parse fails and control returns early.
std::unique_ptr<Block> inflightBlock;
// If a block has yet to be set, this is a new definition. If the caller
// provided a block, use it. Otherwise create a new one.
if (!blockAndLoc.block) {
if (block) {
blockAndLoc.block = block;
} else {
inflightBlock = std::make_unique<Block>();
blockAndLoc.block = inflightBlock.get();
}
// Otherwise, the block has a forward declaration. Forward declarations are
// removed once defined, so if we are defining a existing block and it is
// not a forward declaration, then it is a redeclaration. Fail if the block
// was already defined.
} else if (!eraseForwardRef(blockAndLoc.block)) {
return emitError(nameLoc, "redefinition of block '") << name << "'";
}
// Populate the high level assembly state if necessary.
if (state.asmState)
state.asmState->addDefinition(blockAndLoc.block, nameLoc);
block = blockAndLoc.block;
// If an argument list is present, parse it.
if (getToken().is(Token::l_paren))
@ -1967,7 +1990,10 @@ ParseResult OperationParser::parseBlock(Block *&block) {
if (parseToken(Token::colon, "expected ':' after block name"))
return failure();
return parseBlockBody(block);
ParseResult res = parseBlockBody(block);
if (succeeded(res))
inflightBlock.release();
return res;
}
ParseResult OperationParser::parseBlockBody(Block *block) {
@ -1999,32 +2025,6 @@ Block *OperationParser::getBlockNamed(StringRef name, SMLoc loc) {
return blockDef.block;
}
/// Define the block with the specified name. Returns the Block* or nullptr in
/// the case of redefinition.
Block *OperationParser::defineBlockNamed(StringRef name, SMLoc loc,
Block *existing) {
auto &blockAndLoc = getBlockInfoByName(name);
blockAndLoc.loc = loc;
// If a block has yet to be set, this is a new definition. If the caller
// provided a block, use it. Otherwise create a new one.
if (!blockAndLoc.block) {
blockAndLoc.block = existing ? existing : new Block();
// Otherwise, the block has a forward declaration. Forward declarations are
// removed once defined, so if we are defining a existing block and it is
// not a forward declaration, then it is a redeclaration.
} else if (!eraseForwardRef(blockAndLoc.block)) {
return nullptr;
}
// Populate the high level assembly state if necessary.
if (state.asmState)
state.asmState->addDefinition(blockAndLoc.block, loc);
return blockAndLoc.block;
}
/// Parse a (possibly empty) list of SSA operands with types as block arguments
/// enclosed in parentheses.
///

View File

@ -111,3 +111,10 @@ func @invalid_splat(%v : f32) { // expected-note {{prior use here}}
// expected-error@-1 {{expects different type than prior uses}}
return
}
// -----
// Case that resulted in leak previously.
// expected-error@+1 {{expected ':' after block name}}
"g"()({^a:^b })