aboutsummaryrefslogtreecommitdiff
path: root/flang/lib/Semantics/check-omp-structure.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'flang/lib/Semantics/check-omp-structure.cpp')
-rw-r--r--flang/lib/Semantics/check-omp-structure.cpp118
1 files changed, 115 insertions, 3 deletions
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index db030bb..e224e06 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -351,6 +351,17 @@ bool OmpStructureChecker::IsCloselyNestedRegion(const OmpDirectiveSet &set) {
return false;
}
+bool OmpStructureChecker::IsNestedInDirective(llvm::omp::Directive directive) {
+ if (dirContext_.size() >= 1) {
+ for (size_t i = dirContext_.size() - 1; i > 0; --i) {
+ if (dirContext_[i - 1].directive == directive) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
void OmpStructureChecker::CheckVariableListItem(
const SymbolSourceMap &symbols) {
for (auto &[symbol, source] : symbols) {
@@ -1880,13 +1891,90 @@ void OmpStructureChecker::Enter(const parser::OmpClause::At &x) {
}
}
+// Goes through the names in an OmpObjectList and checks if each name appears
+// in the given allocate statement
+void OmpStructureChecker::CheckAllNamesInAllocateStmt(
+ const parser::CharBlock &source, const parser::OmpObjectList &ompObjectList,
+ const parser::AllocateStmt &allocate) {
+ for (const auto &obj : ompObjectList.v) {
+ if (const auto *d{std::get_if<parser::Designator>(&obj.u)}) {
+ if (const auto *ref{std::get_if<parser::DataRef>(&d->u)}) {
+ if (const auto *n{std::get_if<parser::Name>(&ref->u)}) {
+ CheckNameInAllocateStmt(source, *n, allocate);
+ }
+ }
+ }
+ }
+}
+
+void OmpStructureChecker::CheckNameInAllocateStmt(
+ const parser::CharBlock &source, const parser::Name &name,
+ const parser::AllocateStmt &allocate) {
+ for (const auto &allocation :
+ std::get<std::list<parser::Allocation>>(allocate.t)) {
+ const auto &allocObj = std::get<parser::AllocateObject>(allocation.t);
+ if (const auto *n{std::get_if<parser::Name>(&allocObj.u)}) {
+ if (n->source == name.source) {
+ return;
+ }
+ }
+ }
+ unsigned version{context_.langOptions().OpenMPVersion};
+ context_.Say(source,
+ "Object '%s' in %s directive not "
+ "found in corresponding ALLOCATE statement"_err_en_US,
+ name.ToString(),
+ parser::ToUpperCaseLetters(
+ llvm::omp::getOpenMPDirectiveName(GetContext().directive, version)
+ .str()));
+}
+
void OmpStructureChecker::Enter(const parser::OpenMPExecutableAllocate &x) {
- isPredefinedAllocator = true;
const auto &dir{std::get<parser::Verbatim>(x.t)};
- const auto &objectList{std::get<std::optional<parser::OmpObjectList>>(x.t)};
PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_allocate);
+
+ unsigned version{context_.langOptions().OpenMPVersion};
+ if (version >= 52) {
+ context_.Warn(common::UsageWarning::OpenMPUsage, x.source,
+ "The executable form of the OpenMP ALLOCATE directive has been deprecated, please use ALLOCATORS instead"_warn_en_US);
+ }
+
+ bool hasAllocator = false;
+ // TODO: Investigate whether searching the clause list can be done with
+ // parser::Unwrap instead of the following loop
const auto &clauseList{std::get<parser::OmpClauseList>(x.t)};
for (const auto &clause : clauseList.v) {
+ if (std::get_if<parser::OmpClause::Allocator>(&clause.u)) {
+ hasAllocator = true;
+ }
+ }
+
+ if (IsNestedInDirective(llvm::omp::Directive::OMPD_target) && !hasAllocator) {
+ // TODO: expand this check to exclude the case when a requires
+ // directive with the dynamic_allocators clause is present
+ // in the same compilation unit (OMP5.0 2.11.3).
+ context_.Say(x.source,
+ "ALLOCATE directives that appear in a TARGET region must specify an allocator clause"_err_en_US);
+ }
+
+ const auto &allocateStmt =
+ std::get<parser::Statement<parser::AllocateStmt>>(x.t).statement;
+ if (const auto &list{std::get<std::optional<parser::OmpObjectList>>(x.t)}) {
+ CheckAllNamesInAllocateStmt(
+ std::get<parser::Verbatim>(x.t).source, *list, allocateStmt);
+ }
+ if (const auto &subDirs{
+ std::get<std::optional<std::list<parser::OpenMPDeclarativeAllocate>>>(
+ x.t)}) {
+ for (const auto &dalloc : *subDirs) {
+ CheckAllNamesInAllocateStmt(std::get<parser::Verbatim>(dalloc.t).source,
+ std::get<parser::OmpObjectList>(dalloc.t), allocateStmt);
+ }
+ }
+
+ isPredefinedAllocator = true;
+ const auto &objectList{std::get<std::optional<parser::OmpObjectList>>(x.t)};
+ for (const auto &clause : clauseList.v) {
CheckAlignValue(clause);
}
if (objectList) {
@@ -1920,7 +2008,31 @@ void OmpStructureChecker::Enter(const parser::OpenMPAllocatorsConstruct &x) {
const auto *allocate{
action ? parser::Unwrap<parser::AllocateStmt>(action.stmt) : nullptr};
- if (!allocate) {
+ if (allocate) {
+ for (const auto &clause : dirSpec.Clauses().v) {
+ if (auto *alloc{std::get_if<parser::OmpClause::Allocate>(&clause.u)}) {
+ CheckAllNamesInAllocateStmt(
+ x.source, std::get<parser::OmpObjectList>(alloc->v.t), *allocate);
+
+ using OmpAllocatorSimpleModifier = parser::OmpAllocatorSimpleModifier;
+ using OmpAllocatorComplexModifier = parser::OmpAllocatorComplexModifier;
+
+ auto &modifiers{OmpGetModifiers(alloc->v)};
+ bool hasAllocator{
+ OmpGetUniqueModifier<OmpAllocatorSimpleModifier>(modifiers) ||
+ OmpGetUniqueModifier<OmpAllocatorComplexModifier>(modifiers)};
+
+ // TODO: As with allocate directive, exclude the case when a requires
+ // directive with the dynamic_allocators clause is present in
+ // the same compilation unit (OMP5.0 2.11.3).
+ if (IsNestedInDirective(llvm::omp::Directive::OMPD_target) &&
+ !hasAllocator) {
+ context_.Say(x.source,
+ "ALLOCATORS directives that appear in a TARGET region must specify an allocator"_err_en_US);
+ }
+ }
+ }
+ } else {
const parser::CharBlock &source = action ? action.source : x.source;
context_.Say(source,
"The body of the ALLOCATORS construct should be an ALLOCATE statement"_err_en_US);