Check for loosely-strictured block instead of maintaining a flag

This commit is contained in:
Tom Eccles 2025-08-21 15:46:19 +00:00
parent 040a19d127
commit 16662ce212
4 changed files with 19 additions and 16 deletions

View File

@ -713,7 +713,6 @@ public:
NODE(parser, OmpEndDirective)
NODE(parser, OpenMPAtomicConstruct)
NODE(parser, OpenMPBlockConstruct)
NODE_ENUM(OpenMPBlockConstruct, Flags)
NODE(parser, OpenMPCancelConstruct)
NODE(parser, OpenMPCancellationPointConstruct)
NODE(parser, OpenMPConstruct)

View File

@ -4783,25 +4783,15 @@ struct OmpEndDirective : public OmpDirectiveSpecification {
// Common base class for block-associated constructs.
struct OmpBlockConstruct {
TUPLE_CLASS_BOILERPLATE(OmpBlockConstruct);
ENUM_CLASS(Flags, None, MissingMandatoryEndDirective);
/// Constructor with defualt value for Flags.
OmpBlockConstruct(OmpBeginDirective &&begin, Block &&block,
std::optional<OmpEndDirective> &&end)
: t(std::move(begin), std::move(block), std::move(end), Flags::None) {}
const OmpBeginDirective &BeginDir() const {
return std::get<OmpBeginDirective>(t);
}
const std::optional<OmpEndDirective> &EndDir() const {
return std::get<std::optional<OmpEndDirective>>(t);
}
bool isMissingMandatoryEndDirecitive() const {
return std::get<Flags>(t) == Flags::MissingMandatoryEndDirective;
}
CharBlock source;
std::tuple<OmpBeginDirective, Block, std::optional<OmpEndDirective>, Flags> t;
std::tuple<OmpBeginDirective, Block, std::optional<OmpEndDirective>> t;
};
struct OmpMetadirectiveDirective {

View File

@ -1474,7 +1474,6 @@ struct OmpBlockConstructParser {
constexpr OmpBlockConstructParser(llvm::omp::Directive dir) : dir_(dir) {}
std::optional<resultType> Parse(ParseState &state) const {
using Flags = OmpBlockConstruct::Flags;
if (auto &&begin{OmpBeginDirectiveParser(dir_).Parse(state)}) {
if (auto &&body{attempt(StrictlyStructuredBlockParser{}).Parse(state)}) {
// Try strictly-structured block with an optional end-directive
@ -1503,8 +1502,7 @@ struct OmpBlockConstructParser {
return OmpBlockConstruct{OmpBeginDirective(std::move(*begin)),
std::move(*body),
llvm::transformOptional(std::move(*end),
[](auto &&s) { return OmpEndDirective(std::move(s)); }),
endPresent ? Flags::None : Flags::MissingMandatoryEndDirective};
[](auto &&s) { return OmpEndDirective(std::move(s)); })};
}
}
return std::nullopt;

View File

@ -788,7 +788,23 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
// Missing mandatory end block: this is checked in semantics because that
// makes it easier to control the error messages.
if (x.isMissingMandatoryEndDirecitive()) {
// The end block is mandatory when the construct is not applied to a strictly
// structured block (aka it is applied to a loosely structured block). In
// other words, the body doesn't contain exactly one parser::BlockConstruct.
auto isStrictlyStructuredBlock{[](const parser::Block &block) -> bool {
if (block.size() != 1) {
return false;
}
const parser::ExecutionPartConstruct &contents{block.front()};
auto *executableConstruct{
std::get_if<parser::ExecutableConstruct>(&contents.u)};
if (!executableConstruct) {
return false;
}
return std::holds_alternative<common::Indirection<parser::BlockConstruct>>(
executableConstruct->u);
}};
if (!endSpec && !isStrictlyStructuredBlock(block)) {
context_.Say(
x.BeginDir().source, "Expected OpenMP end directive"_err_en_US);
}