[flang-commits] [flang] 4062618 - [flang][NFC] Unify OpenMP and OpenACC structure checker
via flang-commits
flang-commits at lists.llvm.org
Wed Aug 5 11:25:57 PDT 2020
Author: Valentin Clement
Date: 2020-08-05T14:25:49-04:00
New Revision: 40626184cf95a08f8c62192fa19cd8a71a476206
URL: https://github.com/llvm/llvm-project/commit/40626184cf95a08f8c62192fa19cd8a71a476206
DIFF: https://github.com/llvm/llvm-project/commit/40626184cf95a08f8c62192fa19cd8a71a476206.diff
LOG: [flang][NFC] Unify OpenMP and OpenACC structure checker
This patch remove duplicated code between the check-omp-structure and the check-acc-structure
and unify it into a check-directive-structure templated class.
Reviewed By: kiranchandramohan, sscalpone, ichoyjx
Differential Revision: https://reviews.llvm.org/D85104
Added:
flang/lib/Semantics/check-directive-structure.h
Modified:
flang/lib/Semantics/check-acc-structure.cpp
flang/lib/Semantics/check-acc-structure.h
flang/lib/Semantics/check-omp-structure.cpp
flang/lib/Semantics/check-omp-structure.h
flang/test/Semantics/acc-clause-validity.f90
flang/test/Semantics/omp-clause-validity01.f90
flang/test/Semantics/omp-declarative-directive.f90
llvm/test/TableGen/directive1.td
llvm/test/TableGen/directive2.td
llvm/utils/TableGen/DirectiveEmitter.cpp
Removed:
################################################################################
diff --git a/flang/lib/Semantics/check-acc-structure.cpp b/flang/lib/Semantics/check-acc-structure.cpp
index 974c9dc59abe..46ccc2b762f5 100644
--- a/flang/lib/Semantics/check-acc-structure.cpp
+++ b/flang/lib/Semantics/check-acc-structure.cpp
@@ -132,7 +132,7 @@ void AccStructureChecker::Leave(const parser::OpenACCBlockConstruct &x) {
default:
break;
}
- accContext_.pop_back();
+ dirContext_.pop_back();
}
void AccStructureChecker::CheckNoBranching(const parser::Block &block,
@@ -152,7 +152,7 @@ void AccStructureChecker::Leave(
const parser::OpenACCStandaloneDeclarativeConstruct &) {
// Restriction - 2075
CheckAtLeastOneClause();
- accContext_.pop_back();
+ dirContext_.pop_back();
}
void AccStructureChecker::Enter(const parser::OpenACCCombinedConstruct &x) {
@@ -185,12 +185,7 @@ void AccStructureChecker::Leave(const parser::OpenACCCombinedConstruct &x) {
default:
break;
}
- accContext_.pop_back();
-}
-
-std::string AccStructureChecker::ContextDirectiveAsFortran() {
- return parser::ToUpperCaseLetters(
- llvm::acc::getOpenACCDirectiveName(GetContext().directive).str());
+ dirContext_.pop_back();
}
void AccStructureChecker::Enter(const parser::OpenACCLoopConstruct &x) {
@@ -211,7 +206,7 @@ void AccStructureChecker::Leave(const parser::OpenACCLoopConstruct &x) {
{llvm::acc::Clause::ACCC_gang, llvm::acc::Clause::ACCC_vector,
llvm::acc::Clause::ACCC_worker});
}
- accContext_.pop_back();
+ dirContext_.pop_back();
}
void AccStructureChecker::Enter(const parser::OpenACCStandaloneConstruct &x) {
@@ -238,7 +233,7 @@ void AccStructureChecker::Leave(const parser::OpenACCStandaloneConstruct &x) {
default:
break;
}
- accContext_.pop_back();
+ dirContext_.pop_back();
}
void AccStructureChecker::Enter(const parser::OpenACCRoutineConstruct &x) {
@@ -250,7 +245,7 @@ void AccStructureChecker::Leave(const parser::OpenACCRoutineConstruct &) {
// Restriction - 2407-2408
CheckOnlyAllowedAfter(llvm::acc::Clause::ACCC_device_type,
routineOnlyAllowedAfterDeviceTypeClauses);
- accContext_.pop_back();
+ dirContext_.pop_back();
}
// Clause checkers
@@ -348,154 +343,13 @@ void AccStructureChecker::Enter(const parser::AccClause::Copyout &c) {
}
}
-void AccStructureChecker::CheckAllowed(llvm::acc::Clause clause) {
- if (!GetContext().allowedClauses.test(clause) &&
- !GetContext().allowedOnceClauses.test(clause) &&
- !GetContext().allowedExclusiveClauses.test(clause) &&
- !GetContext().requiredClauses.test(clause)) {
- context_.Say(GetContext().clauseSource,
- "%s clause is not allowed on the %s directive"_err_en_US,
- parser::ToUpperCaseLetters(
- llvm::acc::getOpenACCClauseName(clause).str()),
- parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()));
- return;
- }
- if ((GetContext().allowedOnceClauses.test(clause) ||
- GetContext().allowedExclusiveClauses.test(clause)) &&
- FindClause(clause)) {
- context_.Say(GetContext().clauseSource,
- "At most one %s clause can appear on the %s directive"_err_en_US,
- parser::ToUpperCaseLetters(
- llvm::acc::getOpenACCClauseName(clause).str()),
- parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()));
- return;
- }
- if (GetContext().allowedExclusiveClauses.test(clause)) {
- std::vector<llvm::acc::Clause> others;
- GetContext().allowedExclusiveClauses.IterateOverMembers(
- [&](llvm::acc::Clause o) {
- if (FindClause(o)) {
- others.emplace_back(o);
- }
- });
- for (const auto &e : others) {
- context_.Say(GetContext().clauseSource,
- "%s and %s clauses are mutually exclusive and may not appear on the "
- "same %s directive"_err_en_US,
- parser::ToUpperCaseLetters(
- llvm::acc::getOpenACCClauseName(clause).str()),
- parser::ToUpperCaseLetters(llvm::acc::getOpenACCClauseName(e).str()),
- parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()));
- }
- if (!others.empty()) {
- return;
- }
- }
- SetContextClauseInfo(clause);
- AddClauseToCrtContext(clause);
-}
-
-void AccStructureChecker::CheckOnlyAllowedAfter(
- llvm::acc::Clause clause, AccClauseSet set) {
- bool enforceCheck = false;
- for (auto cl : GetContext().actualClauses) {
- if (cl == clause) {
- enforceCheck = true;
- continue;
- } else if (enforceCheck && !set.test(cl)) {
- auto parserClause = GetContext().clauseInfo.find(cl);
- context_.Say(parserClause->second->source,
- "Clause %s is not allowed after clause %s on the %s "
- "directive"_err_en_US,
- parser::ToUpperCaseLetters(llvm::acc::getOpenACCClauseName(cl).str()),
- parser::ToUpperCaseLetters(
- llvm::acc::getOpenACCClauseName(clause).str()),
- ContextDirectiveAsFortran());
- }
- }
-}
-
-void AccStructureChecker::CheckRequireAtLeastOneOf() {
- for (auto cl : GetContext().actualClauses) {
- if (GetContext().requiredClauses.test(cl))
- return;
- }
- // No clause matched in the actual clauses list
- context_.Say(GetContext().directiveSource,
- "At least one of %s clause must appear on the %s directive"_err_en_US,
- ClauseSetToString(GetContext().requiredClauses),
- ContextDirectiveAsFortran());
-}
-
-void AccStructureChecker::CheckAtLeastOneClause() {
- if (GetContext().actualClauses.empty()) {
- context_.Say(GetContext().directiveSource,
- "At least one clause is required on the %s directive"_err_en_US,
- ContextDirectiveAsFortran());
- }
-}
-
-// Enforce restriction where clauses in the given set are not allowed if the
-// given clause appears.
-void AccStructureChecker::CheckNotAllowedIfClause(
- llvm::acc::Clause clause, AccClauseSet set) {
- if (std::find(GetContext().actualClauses.begin(),
- GetContext().actualClauses.end(),
- clause) == GetContext().actualClauses.end()) {
- return; // Clause is not present
- }
-
- for (auto cl : GetContext().actualClauses) {
- if (set.test(cl)) {
- context_.Say(GetContext().directiveSource,
- "Clause %s is not allowed if clause %s appears on the %s directive"_err_en_US,
- parser::ToUpperCaseLetters(llvm::acc::getOpenACCClauseName(cl).str()),
- parser::ToUpperCaseLetters(
- llvm::acc::getOpenACCClauseName(clause).str()),
- ContextDirectiveAsFortran());
- }
- }
-}
-
-void AccStructureChecker::RequiresConstantPositiveParameter(
- const llvm::acc::Clause &clause, const parser::ScalarIntConstantExpr &i) {
- if (const auto v{GetIntValue(i)}) {
- if (*v <= 0) {
- context_.Say(GetContext().clauseSource,
- "The parameter of the %s clause on the %s directive must be "
- "a constant positive integer expression"_err_en_US,
- parser::ToUpperCaseLetters(
- llvm::acc::getOpenACCClauseName(clause).str()),
- ContextDirectiveAsFortran());
- }
- }
-}
-
-void AccStructureChecker::OptionalConstantPositiveParameter(
- const llvm::acc::Clause &clause,
- const std::optional<parser::ScalarIntConstantExpr> &o) {
- if (o != std::nullopt) {
- RequiresConstantPositiveParameter(clause, o.value());
- }
-}
-
-std::string AccStructureChecker::ClauseSetToString(const AccClauseSet set) {
- std::string list;
- set.IterateOverMembers([&](llvm::acc::Clause o) {
- if (!list.empty())
- list.append(", ");
- list.append(
- parser::ToUpperCaseLetters(llvm::acc::getOpenACCClauseName(o).str()));
- });
- return list;
+llvm::StringRef AccStructureChecker::getClauseName(llvm::acc::Clause clause) {
+ return llvm::acc::getOpenACCClauseName(clause);
}
-void AccStructureChecker::SayNotMatching(
- const parser::CharBlock &beginSource, const parser::CharBlock &endSource) {
- context_
- .Say(endSource, "Unmatched %s directive"_err_en_US,
- parser::ToUpperCaseLetters(endSource.ToString()))
- .Attach(beginSource, "Does not match directive"_en_US);
+llvm::StringRef AccStructureChecker::getDirectiveName(
+ llvm::acc::Directive directive) {
+ return llvm::acc::getOpenACCDirectiveName(directive);
}
} // namespace Fortran::semantics
diff --git a/flang/lib/Semantics/check-acc-structure.h b/flang/lib/Semantics/check-acc-structure.h
index fef12383952d..1ce6e9052b03 100644
--- a/flang/lib/Semantics/check-acc-structure.h
+++ b/flang/lib/Semantics/check-acc-structure.h
@@ -14,13 +14,12 @@
#ifndef FORTRAN_SEMANTICS_CHECK_ACC_STRUCTURE_H_
#define FORTRAN_SEMANTICS_CHECK_ACC_STRUCTURE_H_
+#include "check-directive-structure.h"
#include "flang/Common/enum-set.h"
#include "flang/Parser/parse-tree.h"
#include "flang/Semantics/semantics.h"
#include "llvm/Frontend/OpenACC/ACC.h.inc"
-#include <unordered_map>
-
using AccDirectiveSet = Fortran::common::EnumSet<llvm::acc::Directive,
llvm::acc::Directive_enumSize>;
@@ -32,9 +31,16 @@ using AccClauseSet =
namespace Fortran::semantics {
-class AccStructureChecker : public virtual BaseChecker {
+class AccStructureChecker
+ : public DirectiveStructureChecker<llvm::acc::Directive, llvm::acc::Clause,
+ parser::AccClause, llvm::acc::Clause_enumSize> {
public:
- AccStructureChecker(SemanticsContext &context) : context_{context} {}
+ AccStructureChecker(SemanticsContext &context)
+ : DirectiveStructureChecker(context,
+#define GEN_FLANG_DIRECTIVE_CLAUSE_MAP
+#include "llvm/Frontend/OpenACC/ACC.cpp.inc"
+ ) {
+ }
// Construct and directives
void Enter(const parser::OpenACCBlockConstruct &);
@@ -100,103 +106,13 @@ class AccStructureChecker : public virtual BaseChecker {
void Enter(const parser::AccClause::Write &);
private:
-#define GEN_FLANG_DIRECTIVE_CLAUSE_MAP
-#include "llvm/Frontend/OpenACC/ACC.cpp.inc"
-
- struct AccContext {
- AccContext(parser::CharBlock source, llvm::acc::Directive d)
- : directiveSource{source}, directive{d} {}
-
- parser::CharBlock directiveSource{nullptr};
- parser::CharBlock clauseSource{nullptr};
- llvm::acc::Directive directive;
- AccClauseSet allowedClauses{};
- AccClauseSet allowedOnceClauses{};
- AccClauseSet allowedExclusiveClauses{};
- AccClauseSet requiredClauses{};
-
- const parser::AccClause *clause{nullptr};
- std::multimap<llvm::acc::Clause, const parser::AccClause *> clauseInfo;
- std::list<llvm::acc::Clause> actualClauses;
- };
-
- // back() is the top of the stack
- AccContext &GetContext() {
- CHECK(!accContext_.empty());
- return accContext_.back();
- }
-
- void SetContextClause(const parser::AccClause &clause) {
- GetContext().clauseSource = clause.source;
- GetContext().clause = &clause;
- }
-
- void SetContextClauseInfo(llvm::acc::Clause type) {
- GetContext().clauseInfo.emplace(type, GetContext().clause);
- }
-
- void AddClauseToCrtContext(llvm::acc::Clause type) {
- GetContext().actualClauses.push_back(type);
- }
-
- const parser::AccClause *FindClause(llvm::acc::Clause type) {
- auto it{GetContext().clauseInfo.find(type)};
- if (it != GetContext().clauseInfo.end()) {
- return it->second;
- }
- return nullptr;
- }
-
- void PushContext(const parser::CharBlock &source, llvm::acc::Directive dir) {
- accContext_.emplace_back(source, dir);
- }
-
- void SetClauseSets(llvm::acc::Directive dir) {
- accContext_.back().allowedClauses = directiveClausesTable[dir].allowed;
- accContext_.back().allowedOnceClauses =
- directiveClausesTable[dir].allowedOnce;
- accContext_.back().allowedExclusiveClauses =
- directiveClausesTable[dir].allowedExclusive;
- accContext_.back().requiredClauses =
- directiveClausesTable[dir].requiredOneOf;
- }
- void PushContextAndClauseSets(
- const parser::CharBlock &source, llvm::acc::Directive dir) {
- PushContext(source, dir);
- SetClauseSets(dir);
- }
-
- void SayNotMatching(const parser::CharBlock &, const parser::CharBlock &);
-
- template <typename B> void CheckMatching(const B &beginDir, const B &endDir) {
- const auto &begin{beginDir.v};
- const auto &end{endDir.v};
- if (begin != end) {
- SayNotMatching(beginDir.source, endDir.source);
- }
- }
-
- // Check that only clauses in set are after the specific clauses.
- void CheckOnlyAllowedAfter(llvm::acc::Clause clause, AccClauseSet set);
- void CheckRequireAtLeastOneOf();
- void CheckAllowed(llvm::acc::Clause clause);
- void CheckAtLeastOneClause();
- void CheckNotAllowedIfClause(llvm::acc::Clause clause, AccClauseSet set);
- std::string ContextDirectiveAsFortran();
void CheckNoBranching(const parser::Block &block,
const llvm::acc::Directive directive,
const parser::CharBlock &directiveSource) const;
- void RequiresConstantPositiveParameter(
- const llvm::acc::Clause &clause, const parser::ScalarIntConstantExpr &i);
- void OptionalConstantPositiveParameter(const llvm::acc::Clause &clause,
- const std::optional<parser::ScalarIntConstantExpr> &o);
-
- SemanticsContext &context_;
- std::vector<AccContext> accContext_; // used as a stack
-
- std::string ClauseSetToString(const AccClauseSet set);
+ llvm::StringRef getClauseName(llvm::acc::Clause clause) override;
+ llvm::StringRef getDirectiveName(llvm::acc::Directive directive) override;
};
} // namespace Fortran::semantics
diff --git a/flang/lib/Semantics/check-directive-structure.h b/flang/lib/Semantics/check-directive-structure.h
new file mode 100644
index 000000000000..a5de0564677c
--- /dev/null
+++ b/flang/lib/Semantics/check-directive-structure.h
@@ -0,0 +1,389 @@
+//===-- lib/Semantics/check-directive-structure.h ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Directive structure validity checks common to OpenMP, OpenACC and other
+// directive language.
+
+#ifndef FORTRAN_SEMANTICS_CHECK_DIRECTIVE_STRUCTURE_H_
+#define FORTRAN_SEMANTICS_CHECK_DIRECTIVE_STRUCTURE_H_
+
+#include "flang/Common/enum-set.h"
+#include "flang/Semantics/semantics.h"
+#include "flang/Semantics/tools.h"
+
+#include <unordered_map>
+
+namespace Fortran::semantics {
+
+template <typename C, std::size_t ClauseEnumSize> struct DirectiveClauses {
+ const common::EnumSet<C, ClauseEnumSize> allowed;
+ const common::EnumSet<C, ClauseEnumSize> allowedOnce;
+ const common::EnumSet<C, ClauseEnumSize> allowedExclusive;
+ const common::EnumSet<C, ClauseEnumSize> requiredOneOf;
+};
+
+// Generic structure checker for directives/clauses language such as OpenMP
+// and OpenACC.
+// typename D is the directive enumeration.
+// tyepname C is the clause enumeration.
+// typename PC is the parser class defined in parse-tree.h for the clauses.
+template <typename D, typename C, typename PC, std::size_t ClauseEnumSize>
+class DirectiveStructureChecker : public virtual BaseChecker {
+public:
+ DirectiveStructureChecker(SemanticsContext &context,
+ std::unordered_map<D, DirectiveClauses<C, ClauseEnumSize>>
+ directiveClausesMap)
+ : context_{context}, directiveClausesMap_(directiveClausesMap) {}
+
+protected:
+ struct DirectiveContext {
+ DirectiveContext(parser::CharBlock source, D d)
+ : directiveSource{source}, directive{d} {}
+
+ parser::CharBlock directiveSource{nullptr};
+ parser::CharBlock clauseSource{nullptr};
+ D directive;
+ common::EnumSet<C, ClauseEnumSize> allowedClauses{};
+ common::EnumSet<C, ClauseEnumSize> allowedOnceClauses{};
+ common::EnumSet<C, ClauseEnumSize> allowedExclusiveClauses{};
+ common::EnumSet<C, ClauseEnumSize> requiredClauses{};
+
+ const PC *clause{nullptr};
+ std::multimap<C, const PC *> clauseInfo;
+ std::list<C> actualClauses;
+ };
+
+ // back() is the top of the stack
+ DirectiveContext &GetContext() {
+ CHECK(!dirContext_.empty());
+ return dirContext_.back();
+ }
+
+ void SetContextClause(const PC &clause) {
+ GetContext().clauseSource = clause.source;
+ GetContext().clause = &clause;
+ }
+
+ void ResetPartialContext(const parser::CharBlock &source) {
+ CHECK(!dirContext_.empty());
+ SetContextDirectiveSource(source);
+ GetContext().allowedClauses = {};
+ GetContext().allowedOnceClauses = {};
+ GetContext().allowedExclusiveClauses = {};
+ GetContext().requiredClauses = {};
+ GetContext().clauseInfo = {};
+ }
+
+ void SetContextDirectiveSource(const parser::CharBlock &directive) {
+ GetContext().directiveSource = directive;
+ }
+
+ void SetContextDirectiveEnum(D dir) { GetContext().directive = dir; }
+
+ void SetContextAllowed(const common::EnumSet<C, ClauseEnumSize> &allowed) {
+ GetContext().allowedClauses = allowed;
+ }
+
+ void SetContextAllowedOnce(
+ const common::EnumSet<C, ClauseEnumSize> &allowedOnce) {
+ GetContext().allowedOnceClauses = allowedOnce;
+ }
+
+ void SetContextAllowedExclusive(
+ const common::EnumSet<C, ClauseEnumSize> &allowedExclusive) {
+ GetContext().allowedExclusiveClauses = allowedExclusive;
+ }
+
+ void SetContextRequired(const common::EnumSet<C, ClauseEnumSize> &required) {
+ GetContext().requiredClauses = required;
+ }
+
+ void SetContextClauseInfo(C type) {
+ GetContext().clauseInfo.emplace(type, GetContext().clause);
+ }
+
+ void AddClauseToCrtContext(C type) {
+ GetContext().actualClauses.push_back(type);
+ }
+
+ const PC *FindClause(C type) {
+ auto it{GetContext().clauseInfo.find(type)};
+ if (it != GetContext().clauseInfo.end()) {
+ return it->second;
+ }
+ return nullptr;
+ }
+
+ void PushContext(const parser::CharBlock &source, D dir) {
+ dirContext_.emplace_back(source, dir);
+ }
+
+ bool CurrentDirectiveIsNested() { return dirContext_.size() > 0; };
+
+ void SetClauseSets(D dir) {
+ dirContext_.back().allowedClauses = directiveClausesMap_[dir].allowed;
+ dirContext_.back().allowedOnceClauses =
+ directiveClausesMap_[dir].allowedOnce;
+ dirContext_.back().allowedExclusiveClauses =
+ directiveClausesMap_[dir].allowedExclusive;
+ dirContext_.back().requiredClauses =
+ directiveClausesMap_[dir].requiredOneOf;
+ }
+ void PushContextAndClauseSets(const parser::CharBlock &source, D dir) {
+ PushContext(source, dir);
+ SetClauseSets(dir);
+ }
+
+ void SayNotMatching(const parser::CharBlock &, const parser::CharBlock &);
+
+ template <typename B> void CheckMatching(const B &beginDir, const B &endDir) {
+ const auto &begin{beginDir.v};
+ const auto &end{endDir.v};
+ if (begin != end) {
+ SayNotMatching(beginDir.source, endDir.source);
+ }
+ }
+
+ // Check that only clauses in set are after the specific clauses.
+ void CheckOnlyAllowedAfter(C clause, common::EnumSet<C, ClauseEnumSize> set);
+
+ void CheckRequired(C clause);
+
+ void CheckRequireAtLeastOneOf();
+
+ void CheckAllowed(C clause);
+
+ void CheckAtLeastOneClause();
+
+ void CheckNotAllowedIfClause(
+ C clause, common::EnumSet<C, ClauseEnumSize> set);
+
+ std::string ContextDirectiveAsFortran();
+
+ void RequiresConstantPositiveParameter(
+ const C &clause, const parser::ScalarIntConstantExpr &i);
+
+ void RequiresPositiveParameter(
+ const C &clause, const parser::ScalarIntExpr &i);
+
+ void OptionalConstantPositiveParameter(
+ const C &clause, const std::optional<parser::ScalarIntConstantExpr> &o);
+
+ virtual llvm::StringRef getClauseName(C clause) { return ""; };
+
+ virtual llvm::StringRef getDirectiveName(D directive) { return ""; };
+
+ SemanticsContext &context_;
+ std::vector<DirectiveContext> dirContext_; // used as a stack
+ std::unordered_map<D, DirectiveClauses<C, ClauseEnumSize>>
+ directiveClausesMap_;
+
+ std::string ClauseSetToString(const common::EnumSet<C, ClauseEnumSize> set);
+};
+
+// Check that only clauses included in the given set are present after the given
+// clause.
+template <typename D, typename C, typename PC, std::size_t ClauseEnumSize>
+void DirectiveStructureChecker<D, C, PC, ClauseEnumSize>::CheckOnlyAllowedAfter(
+ C clause, common::EnumSet<C, ClauseEnumSize> set) {
+ bool enforceCheck = false;
+ for (auto cl : GetContext().actualClauses) {
+ if (cl == clause) {
+ enforceCheck = true;
+ continue;
+ } else if (enforceCheck && !set.test(cl)) {
+ auto parserClause = GetContext().clauseInfo.find(cl);
+ context_.Say(parserClause->second->source,
+ "Clause %s is not allowed after clause %s on the %s "
+ "directive"_err_en_US,
+ parser::ToUpperCaseLetters(getClauseName(cl).str()),
+ parser::ToUpperCaseLetters(getClauseName(clause).str()),
+ ContextDirectiveAsFortran());
+ }
+ }
+}
+
+// Check that at least one clause is attached to the directive.
+template <typename D, typename C, typename PC, std::size_t ClauseEnumSize>
+void DirectiveStructureChecker<D, C, PC,
+ ClauseEnumSize>::CheckAtLeastOneClause() {
+ if (GetContext().actualClauses.empty()) {
+ context_.Say(GetContext().directiveSource,
+ "At least one clause is required on the %s directive"_err_en_US,
+ ContextDirectiveAsFortran());
+ }
+}
+
+template <typename D, typename C, typename PC, std::size_t ClauseEnumSize>
+std::string
+DirectiveStructureChecker<D, C, PC, ClauseEnumSize>::ClauseSetToString(
+ const common::EnumSet<C, ClauseEnumSize> set) {
+ std::string list;
+ set.IterateOverMembers([&](C o) {
+ if (!list.empty())
+ list.append(", ");
+ list.append(parser::ToUpperCaseLetters(getClauseName(o).str()));
+ });
+ return list;
+}
+
+// Check that at least one clause in the required set is present on the
+// directive.
+template <typename D, typename C, typename PC, std::size_t ClauseEnumSize>
+void DirectiveStructureChecker<D, C, PC,
+ ClauseEnumSize>::CheckRequireAtLeastOneOf() {
+ for (auto cl : GetContext().actualClauses) {
+ if (GetContext().requiredClauses.test(cl))
+ return;
+ }
+ // No clause matched in the actual clauses list
+ context_.Say(GetContext().directiveSource,
+ "At least one of %s clause must appear on the %s directive"_err_en_US,
+ ClauseSetToString(GetContext().requiredClauses),
+ ContextDirectiveAsFortran());
+}
+
+template <typename D, typename C, typename PC, std::size_t ClauseEnumSize>
+std::string DirectiveStructureChecker<D, C, PC,
+ ClauseEnumSize>::ContextDirectiveAsFortran() {
+ return parser::ToUpperCaseLetters(
+ getDirectiveName(GetContext().directive).str());
+}
+
+// Check that clauses present on the directive are allowed clauses.
+template <typename D, typename C, typename PC, std::size_t ClauseEnumSize>
+void DirectiveStructureChecker<D, C, PC, ClauseEnumSize>::CheckAllowed(
+ C clause) {
+ if (!GetContext().allowedClauses.test(clause) &&
+ !GetContext().allowedOnceClauses.test(clause) &&
+ !GetContext().allowedExclusiveClauses.test(clause) &&
+ !GetContext().requiredClauses.test(clause)) {
+ context_.Say(GetContext().clauseSource,
+ "%s clause is not allowed on the %s directive"_err_en_US,
+ parser::ToUpperCaseLetters(getClauseName(clause).str()),
+ parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()));
+ return;
+ }
+ if ((GetContext().allowedOnceClauses.test(clause) ||
+ GetContext().allowedExclusiveClauses.test(clause)) &&
+ FindClause(clause)) {
+ context_.Say(GetContext().clauseSource,
+ "At most one %s clause can appear on the %s directive"_err_en_US,
+ parser::ToUpperCaseLetters(getClauseName(clause).str()),
+ parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()));
+ return;
+ }
+ if (GetContext().allowedExclusiveClauses.test(clause)) {
+ std::vector<C> others;
+ GetContext().allowedExclusiveClauses.IterateOverMembers([&](C o) {
+ if (FindClause(o)) {
+ others.emplace_back(o);
+ }
+ });
+ for (const auto &e : others) {
+ context_.Say(GetContext().clauseSource,
+ "%s and %s clauses are mutually exclusive and may not appear on the "
+ "same %s directive"_err_en_US,
+ parser::ToUpperCaseLetters(getClauseName(clause).str()),
+ parser::ToUpperCaseLetters(getClauseName(e).str()),
+ parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()));
+ }
+ if (!others.empty()) {
+ return;
+ }
+ }
+ SetContextClauseInfo(clause);
+ AddClauseToCrtContext(clause);
+}
+
+// Enforce restriction where clauses in the given set are not allowed if the
+// given clause appears.
+template <typename D, typename C, typename PC, std::size_t ClauseEnumSize>
+void DirectiveStructureChecker<D, C, PC,
+ ClauseEnumSize>::CheckNotAllowedIfClause(C clause,
+ common::EnumSet<C, ClauseEnumSize> set) {
+ if (std::find(GetContext().actualClauses.begin(),
+ GetContext().actualClauses.end(),
+ clause) == GetContext().actualClauses.end()) {
+ return; // Clause is not present
+ }
+
+ for (auto cl : GetContext().actualClauses) {
+ if (set.test(cl)) {
+ context_.Say(GetContext().directiveSource,
+ "Clause %s is not allowed if clause %s appears on the %s directive"_err_en_US,
+ parser::ToUpperCaseLetters(getClauseName(cl).str()),
+ parser::ToUpperCaseLetters(getClauseName(clause).str()),
+ ContextDirectiveAsFortran());
+ }
+ }
+}
+
+// Check the value of the clause is a constant positive integer.
+template <typename D, typename C, typename PC, std::size_t ClauseEnumSize>
+void DirectiveStructureChecker<D, C, PC,
+ ClauseEnumSize>::RequiresConstantPositiveParameter(const C &clause,
+ const parser::ScalarIntConstantExpr &i) {
+ if (const auto v{GetIntValue(i)}) {
+ if (*v <= 0) {
+ context_.Say(GetContext().clauseSource,
+ "The parameter of the %s clause must be "
+ "a constant positive integer expression"_err_en_US,
+ parser::ToUpperCaseLetters(getClauseName(clause).str()));
+ }
+ }
+}
+
+// Check the value of the clause is a constant positive parameter.
+template <typename D, typename C, typename PC, std::size_t ClauseEnumSize>
+void DirectiveStructureChecker<D, C, PC,
+ ClauseEnumSize>::OptionalConstantPositiveParameter(const C &clause,
+ const std::optional<parser::ScalarIntConstantExpr> &o) {
+ if (o != std::nullopt) {
+ RequiresConstantPositiveParameter(clause, o.value());
+ }
+}
+
+template <typename D, typename C, typename PC, std::size_t ClauseEnumSize>
+void DirectiveStructureChecker<D, C, PC, ClauseEnumSize>::SayNotMatching(
+ const parser::CharBlock &beginSource, const parser::CharBlock &endSource) {
+ context_
+ .Say(endSource, "Unmatched %s directive"_err_en_US,
+ parser::ToUpperCaseLetters(endSource.ToString()))
+ .Attach(beginSource, "Does not match directive"_en_US);
+}
+
+// Check that at least one of the required clauses is present on the directive.
+template <typename D, typename C, typename PC, std::size_t ClauseEnumSize>
+void DirectiveStructureChecker<D, C, PC, ClauseEnumSize>::CheckRequired(C c) {
+ if (!FindClause(c)) {
+ context_.Say(GetContext().directiveSource,
+ "At least one %s clause must appear on the %s directive"_err_en_US,
+ parser::ToUpperCaseLetters(getClauseName(c).str()),
+ ContextDirectiveAsFortran());
+ }
+}
+
+// Check the value of the clause is a positive parameter.
+template <typename D, typename C, typename PC, std::size_t ClauseEnumSize>
+void DirectiveStructureChecker<D, C, PC,
+ ClauseEnumSize>::RequiresPositiveParameter(const C &clause,
+ const parser::ScalarIntExpr &i) {
+ if (const auto v{GetIntValue(i)}) {
+ if (*v <= 0) {
+ context_.Say(GetContext().clauseSource,
+ "The parameter of the %s clause must be "
+ "a positive integer expression"_err_en_US,
+ parser::ToUpperCaseLetters(getClauseName(clause).str()));
+ }
+ }
+}
+
+} // namespace Fortran::semantics
+
+#endif // FORTRAN_SEMANTICS_CHECK_DIRECTIVE_STRUCTURE_H_
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 725dfcd9ced8..b4e4ad46ef95 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -12,21 +12,6 @@
namespace Fortran::semantics {
-std::string OmpStructureChecker::ContextDirectiveAsFortran() {
- auto dir = llvm::omp::getOpenMPDirectiveName(GetContext().directive).str();
- std::transform(dir.begin(), dir.end(), dir.begin(),
- [](unsigned char c) { return std::toupper(c); });
- return dir;
-}
-
-void OmpStructureChecker::SayNotMatching(
- const parser::CharBlock &beginSource, const parser::CharBlock &endSource) {
- context_
- .Say(endSource, "Unmatched %s directive"_err_en_US,
- parser::ToUpperCaseLetters(endSource.ToString()))
- .Attach(beginSource, "Does not match directive"_en_US);
-}
-
bool OmpStructureChecker::HasInvalidWorksharingNesting(
const parser::CharBlock &source, const OmpDirectiveSet &set) {
// set contains all the invalid closely nested directives
@@ -41,85 +26,6 @@ bool OmpStructureChecker::HasInvalidWorksharingNesting(
return false;
}
-void OmpStructureChecker::CheckAllowed(llvm::omp::Clause type) {
- if (!GetContext().allowedClauses.test(type) &&
- !GetContext().allowedOnceClauses.test(type) &&
- !GetContext().allowedExclusiveClauses.test(type) &&
- !GetContext().requiredClauses.test(type)) {
- context_.Say(GetContext().clauseSource,
- "%s clause is not allowed on the %s directive"_err_en_US,
- parser::ToUpperCaseLetters(llvm::omp::getOpenMPClauseName(type).str()),
- parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()));
- return;
- }
- if ((GetContext().allowedOnceClauses.test(type) ||
- GetContext().allowedExclusiveClauses.test(type)) &&
- FindClause(type)) {
- context_.Say(GetContext().clauseSource,
- "At most one %s clause can appear on the %s directive"_err_en_US,
- parser::ToUpperCaseLetters(llvm::omp::getOpenMPClauseName(type).str()),
- parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()));
- return;
- }
- if (GetContext().allowedExclusiveClauses.test(type)) {
- std::vector<llvm::omp::Clause> others;
- GetContext().allowedExclusiveClauses.IterateOverMembers(
- [&](llvm::omp::Clause o) {
- if (FindClause(o)) {
- others.emplace_back(o);
- }
- });
- for (const auto &e : others) {
- context_.Say(GetContext().clauseSource,
- "%s and %s are mutually exclusive and may not appear on the "
- "same %s directive"_err_en_US,
- parser::ToUpperCaseLetters(
- llvm::omp::getOpenMPClauseName(type).str()),
- parser::ToUpperCaseLetters(llvm::omp::getOpenMPClauseName(e).str()),
- parser::ToUpperCaseLetters(GetContext().directiveSource.ToString()));
- }
- if (!others.empty()) {
- return;
- }
- }
- SetContextClauseInfo(type);
-}
-
-void OmpStructureChecker::CheckRequired(llvm::omp::Clause c) {
- if (!FindClause(c)) {
- context_.Say(GetContext().directiveSource,
- "At least one %s clause must appear on the %s directive"_err_en_US,
- parser::ToUpperCaseLetters(llvm::omp::getOpenMPClauseName(c).str()),
- ContextDirectiveAsFortran());
- }
-}
-
-void OmpStructureChecker::RequiresConstantPositiveParameter(
- const llvm::omp::Clause &clause, const parser::ScalarIntConstantExpr &i) {
- if (const auto v{GetIntValue(i)}) {
- if (*v <= 0) {
- context_.Say(GetContext().clauseSource,
- "The parameter of the %s clause must be "
- "a constant positive integer expression"_err_en_US,
- parser::ToUpperCaseLetters(
- llvm::omp::getOpenMPClauseName(clause).str()));
- }
- }
-}
-
-void OmpStructureChecker::RequiresPositiveParameter(
- const llvm::omp::Clause &clause, const parser::ScalarIntExpr &i) {
- if (const auto v{GetIntValue(i)}) {
- if (*v <= 0) {
- context_.Say(GetContext().clauseSource,
- "The parameter of the %s clause must be "
- "a positive integer expression"_err_en_US,
- parser::ToUpperCaseLetters(
- llvm::omp::getOpenMPClauseName(clause).str()));
- }
- }
-}
-
void OmpStructureChecker::Enter(const parser::OpenMPConstruct &) {
// 2.8.1 TODO: Simd Construct with Ordered Construct Nesting check
}
@@ -131,7 +37,10 @@ void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) {
// check matching, End directive is optional
if (const auto &endLoopDir{
std::get<std::optional<parser::OmpEndLoopDirective>>(x.t)}) {
- CheckMatching<parser::OmpLoopDirective>(beginLoopDir, *endLoopDir);
+ const auto &endDir{
+ std::get<parser::OmpLoopDirective>(endLoopDir.value().t)};
+
+ CheckMatching<parser::OmpLoopDirective>(beginDir, endDir);
}
if (beginDir.v != llvm::omp::Directive::OMPD_do) {
@@ -162,7 +71,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) {
}
void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &) {
- ompContext_.pop_back();
+ dirContext_.pop_back();
}
void OmpStructureChecker::Enter(const parser::OmpEndLoopDirective &x) {
@@ -184,28 +93,31 @@ void OmpStructureChecker::Enter(const parser::OmpEndLoopDirective &x) {
void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
const auto &beginBlockDir{std::get<parser::OmpBeginBlockDirective>(x.t)};
const auto &endBlockDir{std::get<parser::OmpEndBlockDirective>(x.t)};
- const auto &beginDir{
- CheckMatching<parser::OmpBlockDirective>(beginBlockDir, endBlockDir)};
+ const auto &beginDir{std::get<parser::OmpBlockDirective>(beginBlockDir.t)};
+ const auto &endDir{std::get<parser::OmpBlockDirective>(endBlockDir.t)};
+ CheckMatching<parser::OmpBlockDirective>(beginDir, endDir);
PushContextAndClauseSets(beginDir.source, beginDir.v);
}
void OmpStructureChecker::Leave(const parser::OpenMPBlockConstruct &) {
- ompContext_.pop_back();
+ dirContext_.pop_back();
}
void OmpStructureChecker::Enter(const parser::OpenMPSectionsConstruct &x) {
const auto &beginSectionsDir{
std::get<parser::OmpBeginSectionsDirective>(x.t)};
const auto &endSectionsDir{std::get<parser::OmpEndSectionsDirective>(x.t)};
- const auto &beginDir{CheckMatching<parser::OmpSectionsDirective>(
- beginSectionsDir, endSectionsDir)};
+ const auto &beginDir{
+ std::get<parser::OmpSectionsDirective>(beginSectionsDir.t)};
+ const auto &endDir{std::get<parser::OmpSectionsDirective>(endSectionsDir.t)};
+ CheckMatching<parser::OmpSectionsDirective>(beginDir, endDir);
PushContextAndClauseSets(beginDir.source, beginDir.v);
}
void OmpStructureChecker::Leave(const parser::OpenMPSectionsConstruct &) {
- ompContext_.pop_back();
+ dirContext_.pop_back();
}
void OmpStructureChecker::Enter(const parser::OmpEndSectionsDirective &x) {
@@ -229,7 +141,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPDeclareSimdConstruct &x) {
}
void OmpStructureChecker::Leave(const parser::OpenMPDeclareSimdConstruct &) {
- ompContext_.pop_back();
+ dirContext_.pop_back();
}
void OmpStructureChecker::Enter(const parser::OpenMPDeclareTargetConstruct &x) {
@@ -243,7 +155,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPDeclareTargetConstruct &x) {
}
void OmpStructureChecker::Leave(const parser::OpenMPDeclareTargetConstruct &) {
- ompContext_.pop_back();
+ dirContext_.pop_back();
}
void OmpStructureChecker::Enter(
@@ -254,7 +166,7 @@ void OmpStructureChecker::Enter(
void OmpStructureChecker::Leave(
const parser::OpenMPSimpleStandaloneConstruct &) {
- ompContext_.pop_back();
+ dirContext_.pop_back();
}
void OmpStructureChecker::Enter(const parser::OpenMPFlushConstruct &x) {
@@ -263,7 +175,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPFlushConstruct &x) {
}
void OmpStructureChecker::Leave(const parser::OpenMPFlushConstruct &) {
- ompContext_.pop_back();
+ dirContext_.pop_back();
}
void OmpStructureChecker::Enter(const parser::OpenMPCancelConstruct &x) {
@@ -272,7 +184,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPCancelConstruct &x) {
}
void OmpStructureChecker::Leave(const parser::OpenMPCancelConstruct &) {
- ompContext_.pop_back();
+ dirContext_.pop_back();
}
void OmpStructureChecker::Enter(
@@ -284,7 +196,7 @@ void OmpStructureChecker::Enter(
void OmpStructureChecker::Leave(
const parser::OpenMPCancellationPointConstruct &) {
- ompContext_.pop_back();
+ dirContext_.pop_back();
}
void OmpStructureChecker::Enter(const parser::OmpEndBlockDirective &x) {
@@ -701,4 +613,14 @@ void OmpStructureChecker::Enter(const parser::OmpScheduleClause &x) {
}
}
}
+
+llvm::StringRef OmpStructureChecker::getClauseName(llvm::omp::Clause clause) {
+ return llvm::omp::getOpenMPClauseName(clause);
+}
+
+llvm::StringRef OmpStructureChecker::getDirectiveName(
+ llvm::omp::Directive directive) {
+ return llvm::omp::getOpenMPDirectiveName(directive);
+}
+
} // namespace Fortran::semantics
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 7fe78a792f19..4dc318429890 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -14,13 +14,12 @@
#ifndef FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
#define FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
+#include "check-directive-structure.h"
#include "flang/Common/enum-set.h"
#include "flang/Parser/parse-tree.h"
#include "flang/Semantics/semantics.h"
#include "llvm/Frontend/OpenMP/OMPConstants.h"
-#include <unordered_map>
-
using OmpDirectiveSet = Fortran::common::EnumSet<llvm::omp::Directive,
llvm::omp::Directive_enumSize>;
@@ -79,9 +78,16 @@ static OmpDirectiveSet taskGeneratingSet{
namespace Fortran::semantics {
-class OmpStructureChecker : public virtual BaseChecker {
+class OmpStructureChecker
+ : public DirectiveStructureChecker<llvm::omp::Directive, llvm::omp::Clause,
+ parser::OmpClause, llvm::omp::Clause_enumSize> {
public:
- OmpStructureChecker(SemanticsContext &context) : context_{context} {}
+ OmpStructureChecker(SemanticsContext &context)
+ : DirectiveStructureChecker(context,
+#define GEN_FLANG_DIRECTIVE_CLAUSE_MAP
+#include "llvm/Frontend/OpenMP/OMP.cpp.inc"
+ ) {
+ }
void Enter(const parser::OpenMPConstruct &);
void Enter(const parser::OpenMPLoopConstruct &);
@@ -156,116 +162,16 @@ class OmpStructureChecker : public virtual BaseChecker {
void Enter(const parser::OmpScheduleClause &);
private:
-#define GEN_FLANG_DIRECTIVE_CLAUSE_MAP
-#include "llvm/Frontend/OpenMP/OMP.cpp.inc"
- struct OmpContext {
- OmpContext(parser::CharBlock source, llvm::omp::Directive d)
- : directiveSource{source}, directive{d} {}
- parser::CharBlock directiveSource{nullptr};
- parser::CharBlock clauseSource{nullptr};
- llvm::omp::Directive directive;
- OmpClauseSet allowedClauses{};
- OmpClauseSet allowedOnceClauses{};
- OmpClauseSet allowedExclusiveClauses{};
- OmpClauseSet requiredClauses{};
-
- const parser::OmpClause *clause{nullptr};
- std::multimap<llvm::omp::Clause, const parser::OmpClause *> clauseInfo;
- };
- // back() is the top of the stack
- OmpContext &GetContext() {
- CHECK(!ompContext_.empty());
- return ompContext_.back();
- }
- // reset source location, check information, and
- // collected information for END directive
- void ResetPartialContext(const parser::CharBlock &source) {
- CHECK(!ompContext_.empty());
- SetContextDirectiveSource(source);
- GetContext().allowedClauses = {};
- GetContext().allowedOnceClauses = {};
- GetContext().allowedExclusiveClauses = {};
- GetContext().requiredClauses = {};
- GetContext().clauseInfo = {};
- }
- void SetContextDirectiveSource(const parser::CharBlock &directive) {
- GetContext().directiveSource = directive;
- }
- void SetContextClause(const parser::OmpClause &clause) {
- GetContext().clauseSource = clause.source;
- GetContext().clause = &clause;
- }
- void SetContextDirectiveEnum(llvm::omp::Directive dir) {
- GetContext().directive = dir;
- }
- void SetContextAllowed(const OmpClauseSet &allowed) {
- GetContext().allowedClauses = allowed;
- }
- void SetContextAllowedOnce(const OmpClauseSet &allowedOnce) {
- GetContext().allowedOnceClauses = allowedOnce;
- }
- void SetContextAllowedExclusive(const OmpClauseSet &allowedExclusive) {
- GetContext().allowedExclusiveClauses = allowedExclusive;
- }
- void SetContextRequired(const OmpClauseSet &required) {
- GetContext().requiredClauses = required;
- }
- void SetContextClauseInfo(llvm::omp::Clause type) {
- GetContext().clauseInfo.emplace(type, GetContext().clause);
- }
- const parser::OmpClause *FindClause(llvm::omp::Clause type) {
- auto it{GetContext().clauseInfo.find(type)};
- if (it != GetContext().clauseInfo.end()) {
- return it->second;
- }
- return nullptr;
- }
- void PushContext(const parser::CharBlock &source, llvm::omp::Directive dir) {
- ompContext_.emplace_back(source, dir);
- }
- void SetClauseSets(llvm::omp::Directive dir) {
- ompContext_.back().allowedClauses = directiveClausesTable[dir].allowed;
- ompContext_.back().allowedOnceClauses =
- directiveClausesTable[dir].allowedOnce;
- ompContext_.back().allowedExclusiveClauses =
- directiveClausesTable[dir].allowedExclusive;
- ompContext_.back().requiredClauses =
- directiveClausesTable[dir].requiredOneOf;
- }
- void PushContextAndClauseSets(
- const parser::CharBlock &source, llvm::omp::Directive dir) {
- PushContext(source, dir);
- SetClauseSets(dir);
- }
- void RequiresConstantPositiveParameter(
- const llvm::omp::Clause &clause, const parser::ScalarIntConstantExpr &i);
- void RequiresPositiveParameter(
- const llvm::omp::Clause &clause, const parser::ScalarIntExpr &i);
-
- bool CurrentDirectiveIsNested() { return ompContext_.size() > 0; };
bool HasInvalidWorksharingNesting(
const parser::CharBlock &, const OmpDirectiveSet &);
- void CheckAllowed(llvm::omp::Clause);
- void CheckRequired(llvm::omp::Clause);
- std::string ContextDirectiveAsFortran();
- void SayNotMatching(const parser::CharBlock &, const parser::CharBlock &);
- template <typename A, typename B, typename C>
- const A &CheckMatching(const B &beginDir, const C &endDir) {
- const A &begin{std::get<A>(beginDir.t)};
- const A &end{std::get<A>(endDir.t)};
- if (begin.v != end.v) {
- SayNotMatching(begin.source, end.source);
- }
- return begin;
- }
// specific clause related
bool ScheduleModifierHasType(const parser::OmpScheduleClause &,
const parser::OmpScheduleModifierType::ModType &);
- SemanticsContext &context_;
- std::vector<OmpContext> ompContext_; // used as a stack
+ llvm::StringRef getClauseName(llvm::omp::Clause clause) override;
+ llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override;
};
} // namespace Fortran::semantics
#endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_
diff --git a/flang/test/Semantics/acc-clause-validity.f90 b/flang/test/Semantics/acc-clause-validity.f90
index a8aefad384b1..75a0efa87d35 100644
--- a/flang/test/Semantics/acc-clause-validity.f90
+++ b/flang/test/Semantics/acc-clause-validity.f90
@@ -82,7 +82,7 @@ program openacc_clause_validity
!$acc end parallel
!$acc parallel
- !ERROR: The parameter of the COLLAPSE clause on the LOOP directive must be a constant positive integer expression
+ !ERROR: The parameter of the COLLAPSE clause must be a constant positive integer expression
!$acc loop collapse(-1)
do i = 1, N
do j = 1, N
diff --git a/flang/test/Semantics/omp-clause-validity01.f90 b/flang/test/Semantics/omp-clause-validity01.f90
index 75050bdc06b5..d1889979527b 100644
--- a/flang/test/Semantics/omp-clause-validity01.f90
+++ b/flang/test/Semantics/omp-clause-validity01.f90
@@ -364,7 +364,7 @@
a = 3.14
enddo
- !ERROR: GRAINSIZE and NUM_TASKS are mutually exclusive and may not appear on the same TASKLOOP directive
+ !ERROR: GRAINSIZE and NUM_TASKS clauses are mutually exclusive and may not appear on the same TASKLOOP directive
!$omp taskloop num_tasks(3) grainsize(2)
do i = 1,N
a = 3.14
@@ -468,7 +468,7 @@
!ERROR: Unmatched END TASKLOOP directive
!$omp end taskloop
- !ERROR: GRAINSIZE and NUM_TASKS are mutually exclusive and may not appear on the same TASKLOOP SIMD directive
+ !ERROR: GRAINSIZE and NUM_TASKS clauses are mutually exclusive and may not appear on the same TASKLOOP SIMD directive
!$omp taskloop simd num_tasks(3) grainsize(2)
do i = 1,N
a = 3.14
diff --git a/flang/test/Semantics/omp-declarative-directive.f90 b/flang/test/Semantics/omp-declarative-directive.f90
index 782cee7c4446..e732cec61f32 100644
--- a/flang/test/Semantics/omp-declarative-directive.f90
+++ b/flang/test/Semantics/omp-declarative-directive.f90
@@ -28,7 +28,7 @@ subroutine declare_simd_2
use m1
procedure (sub) sub1
!ERROR: Internal: no symbol found for 'sub1'
- !ERROR: NOTINBRANCH and INBRANCH are mutually exclusive and may not appear on the same DECLARE SIMD directive
+ !ERROR: NOTINBRANCH and INBRANCH clauses are mutually exclusive and may not appear on the same DECLARE SIMD directive
!$omp declare simd(sub1) inbranch notinbranch
procedure (sub), pointer::p
p=>sub1
diff --git a/llvm/test/TableGen/directive1.td b/llvm/test/TableGen/directive1.td
index 49df4e67b53d..905d6e28c4f9 100644
--- a/llvm/test/TableGen/directive1.td
+++ b/llvm/test/TableGen/directive1.td
@@ -161,15 +161,7 @@ def TDL_DirA : Directive<"dira"> {
// GEN-NEXT: #ifdef GEN_FLANG_DIRECTIVE_CLAUSE_MAP
// GEN-NEXT: #undef GEN_FLANG_DIRECTIVE_CLAUSE_MAP
// GEN-EMPTY:
-// GEN-NEXT: struct TdlDirectiveClauses {
-// GEN-NEXT: const allowed;
-// GEN-NEXT: const allowedOnce;
-// GEN-NEXT: const allowedExclusive;
-// GEN-NEXT: const requiredOneOf;
-// GEN-NEXT: };
-// GEN-EMPTY:
-// GEN-NEXT: std::unordered_map<llvm::tdl::Directive, TdlDirectiveClauses>
-// GEN-NEXT: directiveClausesTable = {
+// GEN-NEXT: {
// GEN-NEXT: {llvm::tdl::Directive::TDLD_dira,
// GEN-NEXT: {
// GEN-NEXT: llvm::tdl::allowedClauses_TDLD_dira,
@@ -178,7 +170,7 @@ def TDL_DirA : Directive<"dira"> {
// GEN-NEXT: llvm::tdl::requiredClauses_TDLD_dira,
// GEN-NEXT: }
// GEN-NEXT: },
-// GEN-NEXT: };
+// GEN-NEXT: }
// GEN-EMPTY:
// GEN-NEXT: #endif // GEN_FLANG_DIRECTIVE_CLAUSE_MAP
diff --git a/llvm/test/TableGen/directive2.td b/llvm/test/TableGen/directive2.td
index e585e11496ef..02f9d4ec40e9 100644
--- a/llvm/test/TableGen/directive2.td
+++ b/llvm/test/TableGen/directive2.td
@@ -152,15 +152,7 @@ def TDL_DirA : Directive<"dira"> {
// GEN-NEXT: #ifdef GEN_FLANG_DIRECTIVE_CLAUSE_MAP
// GEN-NEXT: #undef GEN_FLANG_DIRECTIVE_CLAUSE_MAP
// GEN-EMPTY:
-// GEN-NEXT: struct TdlDirectiveClauses {
-// GEN-NEXT: const allowed;
-// GEN-NEXT: const allowedOnce;
-// GEN-NEXT: const allowedExclusive;
-// GEN-NEXT: const requiredOneOf;
-// GEN-NEXT: };
-// GEN-EMPTY:
-// GEN-NEXT: std::unordered_map<llvm::tdl::Directive, TdlDirectiveClauses>
-// GEN-NEXT: directiveClausesTable = {
+// GEN-NEXT: {
// GEN-NEXT: {llvm::tdl::Directive::TDLD_dira,
// GEN-NEXT: {
// GEN-NEXT: llvm::tdl::allowedClauses_TDLD_dira,
@@ -169,6 +161,6 @@ def TDL_DirA : Directive<"dira"> {
// GEN-NEXT: llvm::tdl::requiredClauses_TDLD_dira,
// GEN-NEXT: }
// GEN-NEXT: },
-// GEN-NEXT: };
+// GEN-NEXT: }
// GEN-EMPTY:
// GEN-NEXT: #endif // GEN_FLANG_DIRECTIVE_CLAUSE_MAP
diff --git a/llvm/utils/TableGen/DirectiveEmitter.cpp b/llvm/utils/TableGen/DirectiveEmitter.cpp
index 0e7f17c35415..60c80eb09d73 100644
--- a/llvm/utils/TableGen/DirectiveEmitter.cpp
+++ b/llvm/utils/TableGen/DirectiveEmitter.cpp
@@ -465,18 +465,7 @@ void GenerateDirectiveClauseMap(const std::vector<Record *> &Directives,
IfDefScope Scope("GEN_FLANG_DIRECTIVE_CLAUSE_MAP", OS);
OS << "\n";
- OS << "struct " << DirLang.getName() << "DirectiveClauses {\n";
- OS << " const " << DirLang.getClauseEnumSetClass() << " allowed;\n";
- OS << " const " << DirLang.getClauseEnumSetClass() << " allowedOnce;\n";
- OS << " const " << DirLang.getClauseEnumSetClass() << " allowedExclusive;\n";
- OS << " const " << DirLang.getClauseEnumSetClass() << " requiredOneOf;\n";
- OS << "};\n";
-
- OS << "\n";
-
- OS << "std::unordered_map<llvm::" << DirLang.getCppNamespace()
- << "::Directive, " << DirLang.getName() << "DirectiveClauses>\n";
- OS << " directiveClausesTable = {\n";
+ OS << "{\n";
for (const auto &D : Directives) {
Directive Dir{D};
@@ -497,7 +486,7 @@ void GenerateDirectiveClauseMap(const std::vector<Record *> &Directives,
OS << " },\n";
}
- OS << "};\n";
+ OS << "}\n";
}
// Generate the implemenation section for the enumeration in the directive
More information about the flang-commits
mailing list