diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index 3c9c5a02a338a6..c18bff26035bbd 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -2739,6 +2739,59 @@ void OmpStructureChecker::Leave(const parser::OmpClauseList &) { llvm::omp::Clause::OMPC_copyprivate, {llvm::omp::Clause::OMPC_nowait}); } + if (GetContext().directive == llvm::omp::Directive::OMPD_task) { + if (auto *d_clause{FindClause(llvm::omp::Clause::OMPC_detach)}) { + // OpenMP 5.0: Task construct restrictions + CheckNotAllowedIfClause( + llvm::omp::Clause::OMPC_detach, {llvm::omp::Clause::OMPC_mergeable}); + + // OpenMP 5.2: Task construct restrictions + if (FindClause(llvm::omp::Clause::OMPC_final)) { + context_.Say(GetContext().clauseSource, + "If a DETACH clause appears on a directive, then the encountering task must not be a FINAL task"_err_en_US); + } + + const auto &detachClause{ + std::get(d_clause->u)}; + if (const auto *name{parser::Unwrap(detachClause.v.v)}) { + if (name->symbol) { + std::string eventHandleSymName{name->ToString()}; + auto checkVarAppearsInDataEnvClause = [&](const parser::OmpObjectList + &objs, + std::string clause) { + for (const auto &obj : objs.v) { + if (const parser::Name *objName{ + parser::Unwrap(obj)}) { + if (objName->ToString() == eventHandleSymName) { + context_.Say(GetContext().clauseSource, + "A variable: `%s` that appears in a DETACH clause cannot appear on %s clause on the same construct"_err_en_US, + eventHandleSymName, clause); + } + } + } + }; + if (auto *dataEnvClause{ + FindClause(llvm::omp::Clause::OMPC_private)}) { + const auto &pClause{ + std::get(dataEnvClause->u)}; + checkVarAppearsInDataEnvClause(pClause.v, "PRIVATE"); + } else if (auto *dataEnvClause{ + FindClause(llvm::omp::Clause::OMPC_firstprivate)}) { + const auto &fpClause{ + std::get(dataEnvClause->u)}; + checkVarAppearsInDataEnvClause(fpClause.v, "FIRSTPRIVATE"); + } else if (auto *dataEnvClause{ + FindClause(llvm::omp::Clause::OMPC_in_reduction)}) { + const auto &irClause{ + std::get(dataEnvClause->u)}; + checkVarAppearsInDataEnvClause( + std::get(irClause.v.t), "IN_REDUCTION"); + } + } + } + } + } + auto testThreadprivateVarErr = [&](Symbol sym, parser::Name name, llvmOmpClause clauseTy) { if (sym.test(Symbol::Flag::OmpThreadprivate)) @@ -2823,7 +2876,6 @@ CHECK_SIMPLE_CLAUSE(Capture, OMPC_capture) CHECK_SIMPLE_CLAUSE(Contains, OMPC_contains) CHECK_SIMPLE_CLAUSE(Default, OMPC_default) CHECK_SIMPLE_CLAUSE(Depobj, OMPC_depobj) -CHECK_SIMPLE_CLAUSE(Detach, OMPC_detach) CHECK_SIMPLE_CLAUSE(DeviceType, OMPC_device_type) CHECK_SIMPLE_CLAUSE(DistSchedule, OMPC_dist_schedule) CHECK_SIMPLE_CLAUSE(Exclusive, OMPC_exclusive) @@ -3352,40 +3404,45 @@ void OmpStructureChecker::CheckIsVarPartOfAnotherVar( const parser::CharBlock &source, const parser::OmpObjectList &objList, llvm::StringRef clause) { for (const auto &ompObject : objList.v) { - common::visit( - common::visitors{ - [&](const parser::Designator &designator) { - if (const auto *dataRef{ - std::get_if(&designator.u)}) { - if (IsDataRefTypeParamInquiry(dataRef)) { + CheckIsVarPartOfAnotherVar(source, ompObject, clause); + } +} + +void OmpStructureChecker::CheckIsVarPartOfAnotherVar( + const parser::CharBlock &source, const parser::OmpObject &ompObject, + llvm::StringRef clause) { + common::visit( + common::visitors{ + [&](const parser::Designator &designator) { + if (const auto *dataRef{ + std::get_if(&designator.u)}) { + if (IsDataRefTypeParamInquiry(dataRef)) { + context_.Say(source, + "A type parameter inquiry cannot appear on the %s " + "directive"_err_en_US, + ContextDirectiveAsFortran()); + } else if (parser::Unwrap( + ompObject) || + parser::Unwrap(ompObject)) { + if (llvm::omp::nonPartialVarSet.test(GetContext().directive)) { context_.Say(source, - "A type parameter inquiry cannot appear on the %s " + "A variable that is part of another variable (as an " + "array or structure element) cannot appear on the %s " "directive"_err_en_US, ContextDirectiveAsFortran()); - } else if (parser::Unwrap( - ompObject) || - parser::Unwrap(ompObject)) { - if (llvm::omp::nonPartialVarSet.test( - GetContext().directive)) { - context_.Say(source, - "A variable that is part of another variable (as an " - "array or structure element) cannot appear on the %s " - "directive"_err_en_US, - ContextDirectiveAsFortran()); - } else { - context_.Say(source, - "A variable that is part of another variable (as an " - "array or structure element) cannot appear in a " - "%s clause"_err_en_US, - clause.data()); - } + } else { + context_.Say(source, + "A variable that is part of another variable (as an " + "array or structure element) cannot appear in a " + "%s clause"_err_en_US, + clause.data()); } } - }, - [&](const parser::Name &name) {}, - }, - ompObject.u); - } + } + }, + [&](const parser::Name &name) {}, + }, + ompObject.u); } void OmpStructureChecker::Enter(const parser::OmpClause::Firstprivate &x) { @@ -3711,6 +3768,30 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Linear &x) { x.v.u); } +void OmpStructureChecker::Enter(const parser::OmpClause::Detach &x) { + // OpenMP 5.0: Task construct restrictions + CheckAllowedClause(llvm::omp::Clause::OMPC_detach); + + // OpenMP 5.2: Detach clause restrictions + CheckIsVarPartOfAnotherVar(GetContext().clauseSource, x.v.v, "DETACH"); + if (const auto *name{parser::Unwrap(x.v.v)}) { + if (name->symbol) { + if (IsPointer(*name->symbol)) { + context_.Say(GetContext().clauseSource, + "The event-handle: `%s` must not have the POINTER attribute"_err_en_US, + name->ToString()); + } + } + auto type{name->symbol->GetType()}; + if (!name->symbol->GetType()->IsNumeric(TypeCategory::Integer) || + evaluate::ToInt64(type->numericTypeSpec().kind()) != 8) { + context_.Say(GetContext().clauseSource, + "The event-handle: `%s` must be of type integer(kind=omp_event_handle_kind)"_err_en_US, + name->ToString()); + } + } +} + void OmpStructureChecker::CheckAllowedMapTypes( const parser::OmpMapType::Value &type, const std::list &allowedMapTypeList) { diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h index 89af46d9171ad3..b8adbc77a8fce0 100644 --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -180,6 +180,8 @@ class OmpStructureChecker const common::Indirection &, const parser::Name &); void CheckDoacross(const parser::OmpDoacross &doa); bool IsDataRefTypeParamInquiry(const parser::DataRef *dataRef); + void CheckIsVarPartOfAnotherVar(const parser::CharBlock &source, + const parser::OmpObject &obj, llvm::StringRef clause = ""); void CheckIsVarPartOfAnotherVar(const parser::CharBlock &source, const parser::OmpObjectList &objList, llvm::StringRef clause = ""); void CheckThreadprivateOrDeclareTargetVar( diff --git a/flang/test/Semantics/OpenMP/detach01.f90 b/flang/test/Semantics/OpenMP/detach01.f90 new file mode 100644 index 00000000000000..e342fcd1b19b4a --- /dev/null +++ b/flang/test/Semantics/OpenMP/detach01.f90 @@ -0,0 +1,65 @@ +! REQUIRES: openmp_runtime +! RUN: %python %S/../test_errors.py %s %flang_fc1 %openmp_flags -fopenmp-version=50 + +! OpenMP Version 5.2 +! Various checks for DETACH Clause (12.5.2) + +program test_detach + use omp_lib + implicit none + integer :: e, x + integer(omp_event_handle_kind) :: event_01, event_02(2) + integer(omp_event_handle_kind), pointer :: event_03 + + + type :: t + integer(omp_event_handle_kind) :: event + end type + + type(t) :: t_01 + + !ERROR: The event-handle: `e` must be of type integer(kind=omp_event_handle_kind) + !$omp task detach(e) + x = x + 1 + !$omp end task + + !ERROR: At most one DETACH clause can appear on the TASK directive + !$omp task detach(event_01) detach(event_01) + x = x + 1 + !$omp end task + + !ERROR: Clause MERGEABLE is not allowed if clause DETACH appears on the TASK directive + !$omp task detach(event_01) mergeable + x = x + 1 + !$omp end task + + !ERROR: If a DETACH clause appears on a directive, then the encountering task must not be a FINAL task + !$omp task detach(event_01) final(.false.) + x = x + 1 + !$omp end task + + !ERROR: A variable: `event_01` that appears in a DETACH clause cannot appear on PRIVATE clause on the same construct + !$omp task detach(event_01) private(event_01) + x = x + 1 + !$omp end task + + !ERROR: A variable: `event_01` that appears in a DETACH clause cannot appear on IN_REDUCTION clause on the same construct + !$omp task detach(event_01) in_reduction(+:event_01) + x = x + 1 + !$omp end task + + !ERROR: A variable that is part of another variable (as an array or structure element) cannot appear in a DETACH clause + !$omp task detach(event_02(1)) + x = x + 1 + !$omp end task + + !ERROR: A variable that is part of another variable (as an array or structure element) cannot appear in a DETACH clause + !$omp task detach(t_01%event) + x = x + 1 + !$omp end task + + !ERROR: The event-handle: `event_03` must not have the POINTER attribute + !$omp task detach(event_03) + x = x + 1 + !$omp end task +end program diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td index bd7fb2361aaeb1..9ada11241d3a56 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMP.td +++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -1085,7 +1085,6 @@ def OMP_Task : Directive<"task"> { VersionedClause, VersionedClause, VersionedClause, - VersionedClause, VersionedClause, VersionedClause, VersionedClause, @@ -1095,6 +1094,7 @@ def OMP_Task : Directive<"task"> { ]; let allowedOnceClauses = [ VersionedClause, + VersionedClause, VersionedClause, VersionedClause, VersionedClause,