diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td --- a/flang/include/flang/Optimizer/Dialect/FIROps.td +++ b/flang/include/flang/Optimizer/Dialect/FIROps.td @@ -2856,7 +2856,8 @@ // Parse the optional table body. mlir::Region *body = result.addRegion(); - if (parser.parseOptionalRegion(*body, llvm::None, llvm::None)) + OptionalParseResult parseResult = parser.parseOptionalRegion(*body); + if (parseResult.hasValue() && failed(*parseResult)) return mlir::failure(); ensureTerminator(*body, parser.getBuilder(), result.location); diff --git a/mlir/include/mlir/IR/OpImplementation.h b/mlir/include/mlir/IR/OpImplementation.h --- a/mlir/include/mlir/IR/OpImplementation.h +++ b/mlir/include/mlir/IR/OpImplementation.h @@ -645,23 +645,23 @@ // Region Parsing //===--------------------------------------------------------------------===// - /// Parses a region. Any parsed blocks are appended to "region" and must be + /// Parses a region. Any parsed blocks are appended to 'region' and must be /// moved to the op regions after the op is created. The first block of the - /// region takes "arguments" of types "argTypes". If "enableNameShadowing" is + /// region takes 'arguments' of types 'argTypes'. If 'enableNameShadowing' is /// set to true, the argument names are allowed to shadow the names of other - /// existing SSA values defined above the region scope. "enableNameShadowing" + /// existing SSA values defined above the region scope. 'enableNameShadowing' /// can only be set to true for regions attached to operations that are - /// "IsolatedFromAbove". + /// 'IsolatedFromAbove. virtual ParseResult parseRegion(Region ®ion, ArrayRef arguments = {}, ArrayRef argTypes = {}, bool enableNameShadowing = false) = 0; /// Parses a region if present. - virtual ParseResult parseOptionalRegion(Region ®ion, - ArrayRef arguments = {}, - ArrayRef argTypes = {}, - bool enableNameShadowing = false) = 0; + virtual OptionalParseResult + parseOptionalRegion(Region ®ion, ArrayRef arguments = {}, + ArrayRef argTypes = {}, + bool enableNameShadowing = false) = 0; /// Parses a region if present. If the region is present, a new region is /// allocated and placed in `region`. If no region is present or on failure, diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -1187,9 +1187,12 @@ return parser.emitError(parser.getNameLoc(), "type can only be omitted for string globals"); } - } else if (parser.parseOptionalRegion(initRegion, /*arguments=*/{}, - /*argTypes=*/{})) { - return failure(); + } else { + OptionalParseResult parseResult = + parser.parseOptionalRegion(initRegion, /*arguments=*/{}, + /*argTypes=*/{}); + if (parseResult.hasValue() && failed(*parseResult)) + return failure(); } result.addAttribute("type", TypeAttr::get(types[0])); @@ -1398,8 +1401,9 @@ resultAttrs); auto *body = result.addRegion(); - return parser.parseOptionalRegion( + OptionalParseResult parseResult = parser.parseOptionalRegion( *body, entryArgs, entryArgs.empty() ? ArrayRef() : argTypes); + return failure(parseResult.hasValue() && failed(*parseResult)); } // Print the LLVMFuncOp. Collects argument and result types and passes them to diff --git a/mlir/lib/Dialect/SPIRV/SPIRVOps.cpp b/mlir/lib/Dialect/SPIRV/SPIRVOps.cpp --- a/mlir/lib/Dialect/SPIRV/SPIRVOps.cpp +++ b/mlir/lib/Dialect/SPIRV/SPIRVOps.cpp @@ -1754,8 +1754,9 @@ // Parse the optional function body. auto *body = state.addRegion(); - return parser.parseOptionalRegion( + OptionalParseResult result = parser.parseOptionalRegion( *body, entryArgs, entryArgs.empty() ? ArrayRef() : argTypes); + return failure(result.hasValue() && failed(*result)); } static void print(spirv::FuncOp fnOp, OpAsmPrinter &printer) { diff --git a/mlir/lib/IR/FunctionImplementation.cpp b/mlir/lib/IR/FunctionImplementation.cpp --- a/mlir/lib/IR/FunctionImplementation.cpp +++ b/mlir/lib/IR/FunctionImplementation.cpp @@ -204,10 +204,21 @@ assert(resultAttrs.size() == resultTypes.size()); addArgAndResultAttrs(builder, result, argAttrs, resultAttrs); - // Parse the optional function body. + // Parse the optional function body. The printer will not print the body if + // its empty, so disallow parsing of empty body in the parser. auto *body = result.addRegion(); - return parser.parseOptionalRegion( - *body, entryArgs, entryArgs.empty() ? ArrayRef() : argTypes); + llvm::SMLoc loc = parser.getCurrentLocation(); + OptionalParseResult parseResult = parser.parseOptionalRegion( + *body, entryArgs, entryArgs.empty() ? ArrayRef() : argTypes, + /*enableNameShadowing=*/false); + if (parseResult.hasValue()) { + if (failed(*parseResult)) + return failure(); + // Function body was parsed, make sure its not empty. + if (body->empty()) + return parser.emitError(loc, "expected non-empty function body"); + } + return success(); } // Print a function result list. diff --git a/mlir/lib/Parser/Parser.cpp b/mlir/lib/Parser/Parser.cpp --- a/mlir/lib/Parser/Parser.cpp +++ b/mlir/lib/Parser/Parser.cpp @@ -1429,12 +1429,12 @@ } /// Parses a region if present. - ParseResult parseOptionalRegion(Region ®ion, - ArrayRef arguments, - ArrayRef argTypes, - bool enableNameShadowing) override { + OptionalParseResult parseOptionalRegion(Region ®ion, + ArrayRef arguments, + ArrayRef argTypes, + bool enableNameShadowing) override { if (parser.getToken().isNot(Token::l_brace)) - return success(); + return llvm::None; return parseRegion(region, arguments, argTypes, enableNameShadowing); } diff --git a/mlir/test/Dialect/SCF/canonicalize.mlir b/mlir/test/Dialect/SCF/canonicalize.mlir --- a/mlir/test/Dialect/SCF/canonicalize.mlir +++ b/mlir/test/Dialect/SCF/canonicalize.mlir @@ -86,7 +86,7 @@ // ----- -func private @side_effect() {} +func private @side_effect() func @all_unused(%cond: i1) { %c0 = constant 0 : index %c1 = constant 1 : index diff --git a/mlir/test/IR/invalid.mlir b/mlir/test/IR/invalid.mlir --- a/mlir/test/IR/invalid.mlir +++ b/mlir/test/IR/invalid.mlir @@ -1572,3 +1572,7 @@ } return } + +// ----- + +func @foo() {} // expected-error {{expected non-empty function body}} diff --git a/mlir/test/IR/traits.mlir b/mlir/test/IR/traits.mlir --- a/mlir/test/IR/traits.mlir +++ b/mlir/test/IR/traits.mlir @@ -344,12 +344,10 @@ // Test that operation with the SymbolTable Trait define a new symbol scope. "test.symbol_scope"() ({ - func private @foo() { - } + func private @foo() "test.finish" () : () -> () }) : () -> () -func private @foo() { -} +func private @foo() // ----- diff --git a/mlir/tools/mlir-tblgen/OpFormatGen.cpp b/mlir/tools/mlir-tblgen/OpFormatGen.cpp --- a/mlir/tools/mlir-tblgen/OpFormatGen.cpp +++ b/mlir/tools/mlir-tblgen/OpFormatGen.cpp @@ -652,8 +652,11 @@ /// /// {0}: The name of the region. const char *optionalRegionParserCode = R"( - if (parser.parseOptionalRegion(*{0}Region)) - return ::mlir::failure(); + { + auto parseResult = parser.parseOptionalRegion(*{0}Region); + if (parseResult.hasValue() && failed(*parseResult)) + return ::mlir::failure(); + } )"; /// The code snippet used to generate a parser call for a region.