Index: flang/include/flang/Semantics/symbol.h =================================================================== --- flang/include/flang/Semantics/symbol.h +++ flang/include/flang/Semantics/symbol.h @@ -502,7 +502,7 @@ // OpenMP data-mapping attribute OmpMapTo, OmpMapFrom, OmpMapAlloc, OmpMapRelease, OmpMapDelete, // OpenMP data-copying attribute - OmpCopyIn, + OmpCopyIn, OmpCopyPrivate, // OpenMP miscellaneous flags OmpCommonBlock, OmpReduction, OmpAllocate, OmpDeclareSimd, OmpDeclareTarget, OmpThreadprivate, OmpDeclareReduction, OmpFlushed, Index: flang/lib/Semantics/check-directive-structure.h =================================================================== --- flang/lib/Semantics/check-directive-structure.h +++ flang/lib/Semantics/check-directive-structure.h @@ -209,6 +209,17 @@ dirContext_.emplace_back(source, dir); } + DirectiveContext *GetEnclosingContextWithDir(D dir) { + CHECK(!dirContext_.empty()); + auto it{dirContext_.rbegin()}; + while (++it != dirContext_.rend()) { + if (it->directive == dir) { + return &(*it); + } + } + return nullptr; + } + bool CurrentDirectiveIsNested() { return dirContext_.size() > 0; }; void SetClauseSets(D dir) { Index: flang/lib/Semantics/check-omp-structure.h =================================================================== --- flang/lib/Semantics/check-omp-structure.h +++ flang/lib/Semantics/check-omp-structure.h @@ -73,11 +73,19 @@ Directive::OMPD_teams_distribute_simd}; static OmpDirectiveSet taskGeneratingSet{ OmpDirectiveSet{Directive::OMPD_task} | taskloopSet}; +static OmpClauseSet privateSet{ + Clause::OMPC_private, Clause::OMPC_firstprivate, Clause::OMPC_lastprivate}; +static OmpClauseSet privateReductionSet{ + OmpClauseSet{Clause::OMPC_reduction} | privateSet}; } // namespace omp } // namespace llvm namespace Fortran::semantics { +using SymbolSourceMap = std::multimap; +using DirectivesClauseTriple = std::multimap>; + class OmpStructureChecker : public DirectiveStructureChecker { @@ -158,8 +166,10 @@ void CheckIsVarPartOfAnotherVar(const parser::OmpObjectList &objList); void CheckIntentInPointer( const parser::OmpObjectList &, const llvm::omp::Clause); - void GetSymbolsInObjectList( - const parser::OmpObjectList &, std::vector &); + void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &); + void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause); + void CheckPrivateSymbolsInOuterCxt( + SymbolSourceMap &, DirectivesClauseTriple &, const llvm::omp::Clause); const parser::Name GetLoopIndex(const parser::DoConstruct *x); void SetLoopInfo(const parser::OpenMPLoopConstruct &x); void CheckIsLoopIvPartOfClause( Index: flang/lib/Semantics/check-omp-structure.cpp =================================================================== --- flang/lib/Semantics/check-omp-structure.cpp +++ flang/lib/Semantics/check-omp-structure.cpp @@ -492,7 +492,6 @@ CHECK_SIMPLE_CLAUSE(Allocate, OMPC_allocate) CHECK_SIMPLE_CLAUSE(Capture, OMPC_capture) CHECK_SIMPLE_CLAUSE(Copyin, OMPC_copyin) -CHECK_SIMPLE_CLAUSE(Copyprivate, OMPC_copyprivate) CHECK_SIMPLE_CLAUSE(Default, OMPC_default) CHECK_SIMPLE_CLAUSE(Depobj, OMPC_depobj) CHECK_SIMPLE_CLAUSE(Destroy, OMPC_destroy) @@ -517,7 +516,6 @@ CHECK_SIMPLE_CLAUSE(Threads, OMPC_threads) CHECK_SIMPLE_CLAUSE(Inbranch, OMPC_inbranch) CHECK_SIMPLE_CLAUSE(IsDevicePtr, OMPC_is_device_ptr) -CHECK_SIMPLE_CLAUSE(Lastprivate, OMPC_lastprivate) CHECK_SIMPLE_CLAUSE(Link, OMPC_link) CHECK_SIMPLE_CLAUSE(Mergeable, OMPC_mergeable) CHECK_SIMPLE_CLAUSE(Nogroup, OMPC_nogroup) @@ -606,7 +604,39 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Firstprivate &x) { CheckAllowed(llvm::omp::Clause::OMPC_firstprivate); CheckIsLoopIvPartOfClause(llvmOmpClause::OMPC_firstprivate, x.v); + + SymbolSourceMap currSymbols; + GetSymbolsInObjectList(x.v, currSymbols); + + DirectivesClauseTriple dirClauseTriple; + // Firstprivate variables on worksharing constructs + dirClauseTriple.emplace(llvm::omp::Directive::OMPD_do, + std::make_pair( + llvm::omp::Directive::OMPD_parallel, llvm::omp::privateReductionSet)); + dirClauseTriple.emplace(llvm::omp::Directive::OMPD_sections, + std::make_pair( + llvm::omp::Directive::OMPD_parallel, llvm::omp::privateReductionSet)); + dirClauseTriple.emplace(llvm::omp::Directive::OMPD_single, + std::make_pair( + llvm::omp::Directive::OMPD_parallel, llvm::omp::privateReductionSet)); + // Firstprivate variables on distribute construct + dirClauseTriple.emplace(llvm::omp::Directive::OMPD_distribute, + std::make_pair( + llvm::omp::Directive::OMPD_teams, llvm::omp::privateReductionSet)); + dirClauseTriple.emplace(llvm::omp::Directive::OMPD_distribute, + std::make_pair(llvm::omp::Directive::OMPD_target_teams, + llvm::omp::privateReductionSet)); + // Firstprivate variables on task and taskloop construct + dirClauseTriple.emplace(llvm::omp::Directive::OMPD_task, + std::make_pair(llvm::omp::Directive::OMPD_parallel, + OmpClauseSet{llvm::omp::Clause::OMPC_reduction})); + dirClauseTriple.emplace(llvm::omp::Directive::OMPD_taskloop, + std::make_pair(llvm::omp::Directive::OMPD_parallel, + OmpClauseSet{llvm::omp::Clause::OMPC_reduction})); + CheckPrivateSymbolsInOuterCxt( + currSymbols, dirClauseTriple, llvm::omp::Clause::OMPC_firstprivate); } + void OmpStructureChecker::CheckIsLoopIvPartOfClause( llvmOmpClause clause, const parser::OmpObjectList &ompObjectList) { for (const auto &ompObject : ompObjectList.v) { @@ -837,6 +867,29 @@ } } +void OmpStructureChecker::Enter(const parser::OmpClause::Copyprivate &x) { + CheckAllowed(llvm::omp::Clause::OMPC_copyprivate); + CheckIntentInPointer(x.v, llvm::omp::Clause::OMPC_copyprivate); +} + +void OmpStructureChecker::Enter(const parser::OmpClause::Lastprivate &x) { + CheckAllowed(llvm::omp::Clause::OMPC_lastprivate); + + DirectivesClauseTriple dirClauseTriple; + SymbolSourceMap currSymbols; + GetSymbolsInObjectList(x.v, currSymbols); + CheckDefinableObjects(currSymbols, llvm::omp::Clause::OMPC_lastprivate); + + dirClauseTriple.emplace(llvm::omp::Directive::OMPD_do, + std::make_pair( + llvm::omp::Directive::OMPD_parallel, llvm::omp::privateReductionSet)); + dirClauseTriple.emplace(llvm::omp::Directive::OMPD_sections, + std::make_pair( + llvm::omp::Directive::OMPD_parallel, llvm::omp::privateReductionSet)); + CheckPrivateSymbolsInOuterCxt( + currSymbols, dirClauseTriple, llvm::omp::Clause::OMPC_lastprivate); +} + llvm::StringRef OmpStructureChecker::getClauseName(llvm::omp::Clause clause) { return llvm::omp::getOpenMPClauseName(clause); } @@ -898,11 +951,13 @@ void OmpStructureChecker::CheckIntentInPointer( const parser::OmpObjectList &objectList, const llvm::omp::Clause clause) { - std::vector symbols; + SymbolSourceMap symbols; GetSymbolsInObjectList(objectList, symbols); - for (const auto *symbol : symbols) { + for (auto it{symbols.begin()}; it != symbols.end(); ++it) { + const auto *symbol{it->first}; + const auto source{it->second}; if (IsPointer(*symbol) && IsIntentIn(*symbol)) { - context_.Say(GetContext().clauseSource, + context_.Say(source, "Pointer '%s' with the INTENT(IN) attribute may not appear " "in a %s clause"_err_en_US, symbol->name(), @@ -912,18 +967,92 @@ } void OmpStructureChecker::GetSymbolsInObjectList( - const parser::OmpObjectList &objectList, - std::vector &symbols) { + const parser::OmpObjectList &objectList, SymbolSourceMap &symbols) { for (const auto &ompObject : objectList.v) { if (const auto *name{parser::Unwrap(ompObject)}) { if (const auto *symbol{name->symbol}) { if (const auto *commonBlockDetails{ symbol->detailsIf()}) { for (const auto &object : commonBlockDetails->objects()) { - symbols.emplace_back(&object->GetUltimate()); + symbols.emplace(&object->GetUltimate(), name->source); } } else { - symbols.emplace_back(&symbol->GetUltimate()); + symbols.emplace(&symbol->GetUltimate(), name->source); + } + } + } + } +} + +void OmpStructureChecker::CheckDefinableObjects( + SymbolSourceMap &symbols, const llvm::omp::Clause clause) { + for (auto it{symbols.begin()}; it != symbols.end(); ++it) { + const auto *symbol{it->first}; + const auto source{it->second}; + if (auto msg{WhyNotModifiable(*symbol, context_.FindScope(source))}) { + context_ + .Say(source, + "Variable '%s' on the %s clause is not definable"_err_en_US, + symbol->name(), + parser::ToUpperCaseLetters(getClauseName(clause).str())) + .Attach(source, std::move(*msg), symbol->name()); + } + } +} + +void OmpStructureChecker::CheckPrivateSymbolsInOuterCxt( + SymbolSourceMap &currSymbols, DirectivesClauseTriple &dirClauseTriple, + const llvm::omp::Clause currClause) { + SymbolSourceMap enclosingSymbols; + auto range{dirClauseTriple.equal_range(GetContext().directive)}; + for (auto dirIter{range.first}; dirIter != range.second; ++dirIter) { + auto enclosingDir{dirIter->second.first}; + auto enclosingClauseSet{dirIter->second.second}; + if (auto *enclosingContext{GetEnclosingContextWithDir(enclosingDir)}) { + for (auto it{enclosingContext->clauseInfo.begin()}; + it != enclosingContext->clauseInfo.end(); ++it) { + std::visit(common::visitors{ + [&](const parser::OmpClause::Private &x) { + if (enclosingClauseSet.test( + llvm::omp::Clause::OMPC_private)) { + GetSymbolsInObjectList(x.v, enclosingSymbols); + } + }, + [&](const parser::OmpClause::Firstprivate &x) { + if (enclosingClauseSet.test( + llvm::omp::Clause::OMPC_firstprivate)) { + GetSymbolsInObjectList(x.v, enclosingSymbols); + } + }, + [&](const parser::OmpClause::Lastprivate &x) { + if (enclosingClauseSet.test( + llvm::omp::Clause::OMPC_lastprivate)) { + GetSymbolsInObjectList(x.v, enclosingSymbols); + } + }, + [&](const parser::OmpClause::Reduction &x) { + if (enclosingClauseSet.test( + llvm::omp::Clause::OMPC_reduction)) { + const auto &ompObjectList{ + std::get(x.v.t)}; + GetSymbolsInObjectList( + ompObjectList, enclosingSymbols); + } + }, + [&](const auto &) {}, + }, + it->second->u); + } + + // Check if the symbols in current context are private in outer context + for (auto iter{currSymbols.begin()}; iter != currSymbols.end(); ++iter) { + const auto *symbol{iter->first}; + const auto source{iter->second}; + if (enclosingSymbols.find(symbol) != enclosingSymbols.end()) { + context_.Say(source, + "%s variable '%s' is PRIVATE in outer context"_err_en_US, + parser::ToUpperCaseLetters(getClauseName(currClause).str()), + symbol->name()); } } } Index: flang/lib/Semantics/resolve-directives.cpp =================================================================== --- flang/lib/Semantics/resolve-directives.cpp +++ flang/lib/Semantics/resolve-directives.cpp @@ -345,6 +345,10 @@ ResolveOmpObjectList(x.v, Symbol::Flag::OmpCopyIn); return false; } + bool Pre(const parser::OmpClause::Copyprivate &x) { + ResolveOmpObjectList(x.v, Symbol::Flag::OmpCopyPrivate); + return false; + } bool Pre(const parser::OmpLinearClause &x) { std::visit(common::visitors{ [&](const parser::OmpLinearClause::WithoutModifier @@ -419,7 +423,7 @@ Symbol::Flag::OmpThreadprivate}; static constexpr Symbol::Flags dataCopyingAttributeFlags{ - Symbol::Flag::OmpCopyIn}; + Symbol::Flag::OmpCopyIn, Symbol::Flag::OmpCopyPrivate}; std::vector allocateNames_; // on one directive SymbolSet privateDataSharingAttributeObjects_; // on one directive @@ -464,7 +468,6 @@ void CheckDataCopyingClause( const parser::Name &, const Symbol &, Symbol::Flag); - void CheckAssocLoopLevel(std::int64_t level, const parser::OmpClause *clause); void CheckPrivateDSAObject( const parser::Name &, const Symbol &, Symbol::Flag); @@ -475,6 +478,7 @@ sourceLabels_.clear(); targetLabels_.clear(); }; + bool HasSymbolInEnclosingScope(const Symbol &, Scope &); }; template @@ -1495,6 +1499,28 @@ context_.Say(name.source, "Non-THREADPRIVATE object '%s' in COPYIN clause"_err_en_US, checkSymbol->name()); + } else if (GetContext().directive == llvm::omp::Directive::OMPD_single) { + // A list item that appears in a 'copyprivate' clause may not appear on a + // 'private' or 'firstprivate' clause on a single construct + if (IsObjectWithDSA(symbol) && + (symbol.test(Symbol::Flag::OmpPrivate) || + symbol.test(Symbol::Flag::OmpFirstPrivate))) { + context_.Say(name.source, + "COPYPRIVATE variable '%s' may not appear on a PRIVATE or " + "FIRSTPRIVATE clause on a SINGLE construct"_err_en_US, + symbol.name()); + } else { + // List of items/objects that can appear in a 'copyprivate' clause must be + // either 'private' or 'threadprivate' in enclosing context. + if (!symbol.test(Symbol::Flag::OmpThreadprivate) && + !(HasSymbolInEnclosingScope(symbol, currScope()) && + symbol.test(Symbol::Flag::OmpPrivate))) { + context_.Say(name.source, + "COPYPRIVATE variable '%s' is not PRIVATE or THREADPRIVATE in " + "outer context"_err_en_US, + symbol.name()); + } + } } } @@ -1570,4 +1596,11 @@ } } +bool OmpAttributeVisitor::HasSymbolInEnclosingScope( + const Symbol &symbol, Scope &scope) { + const auto symbols{scope.parent().GetSymbols()}; + auto it{std::find(symbols.begin(), symbols.end(), symbol)}; + return it != symbols.end(); +} + } // namespace Fortran::semantics Index: flang/test/Semantics/omp-clause-validity01.f90 =================================================================== --- flang/test/Semantics/omp-clause-validity01.f90 +++ flang/test/Semantics/omp-clause-validity01.f90 @@ -322,6 +322,7 @@ !$omp single private(a) lastprivate(c) a = 3.14 !ERROR: Clause NOWAIT is not allowed if clause COPYPRIVATE appears on the END SINGLE directive + !ERROR: COPYPRIVATE variable 'a' may not appear on a PRIVATE or FIRSTPRIVATE clause on a SINGLE construct !ERROR: At most one NOWAIT clause can appear on the END SINGLE directive !$omp end single copyprivate(a) nowait nowait c = 2 @@ -478,14 +479,12 @@ !$omp barrier !$omp taskwait !$omp taskwait depend(source) - !ERROR: Internal: no symbol found for 'i' - !$omp taskwait depend(sink:i-1) + ! !$omp taskwait depend(sink:i-1) ! !$omp target enter data map(to:arrayA) map(alloc:arrayB) ! !$omp target update from(arrayA) to(arrayB) ! !$omp target exit data map(from:arrayA) map(delete:arrayB) !$omp ordered depend(source) - !ERROR: Internal: no symbol found for 'i' - !$omp ordered depend(sink:i-1) + ! !$omp ordered depend(sink:i-1) !$omp flush (c) !$omp flush acq_rel !$omp flush release @@ -502,11 +501,9 @@ ! 2.13.2 critical Construct - !ERROR: Internal: no symbol found for 'first' - !$omp critical (first) + ! !$omp critical (first) a = 3.14 - !ERROR: Internal: no symbol found for 'first' - !$omp end critical (first) + ! !$omp end critical (first) ! 2.9.1 task-clause -> if-clause | ! final-clause | Index: flang/test/Semantics/omp-copyprivate01.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-copyprivate01.f90 @@ -0,0 +1,27 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.15.4.2 copyprivate Clause +! A list item that appears in a copyprivate clause may not appear in a +! private or firstprivate clause on the single construct. + +program omp_copyprivate + integer :: a(10), b(10), k + + k = 10 + a = 10 + b = a * 10 + + !$omp parallel + !$omp single private(k) + a = a + k + !ERROR: COPYPRIVATE variable 'k' may not appear on a PRIVATE or FIRSTPRIVATE clause on a SINGLE construct + !$omp end single copyprivate(k) + !$omp single firstprivate(k) + b = a - k + !ERROR: COPYPRIVATE variable 'k' may not appear on a PRIVATE or FIRSTPRIVATE clause on a SINGLE construct + !$omp end single copyprivate(k) + !$omp end parallel + + print *, a, b + +end program omp_copyprivate Index: flang/test/Semantics/omp-copyprivate02.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-copyprivate02.f90 @@ -0,0 +1,23 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.15.4.2 copyprivate Clause +! Pointers with the INTENT(IN) attribute may not appear in a copyprivate clause. + +subroutine omp_copyprivate(p) + integer :: a(10), b(10), c(10) + integer, pointer, intent(in) :: p + + a = 10 + b = 20 + + !$omp parallel + !$omp single + c = a + b + p + !ERROR: COPYPRIVATE variable 'p' is not PRIVATE or THREADPRIVATE in outer context + !ERROR: Pointer 'p' with the INTENT(IN) attribute may not appear in a COPYPRIVATE clause + !$omp end single copyprivate(p) + !$omp end parallel + + print *, c + +end subroutine omp_copyprivate Index: flang/test/Semantics/omp-copyprivate03.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-copyprivate03.f90 @@ -0,0 +1,39 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.15.4.2 copyprivate Clause +! All list items that appear in the copyprivate clause must be either +! threadprivate or private in the enclosing context. + +program omp_copyprivate + integer :: a(10), b(10) + integer, save :: k + + !$omp threadprivate(k) + + k = 10 + a = 10 + b = a + 10 + + !$omp parallel + !$omp single + a = a + k + !$omp end single copyprivate(k) + !$omp single + b = b - a + !ERROR: COPYPRIVATE variable 'b' is not PRIVATE or THREADPRIVATE in outer context + !$omp end single copyprivate(b) + !$omp end parallel + + !$omp parallel sections private(a) + !$omp section + !$omp parallel + !$omp single + a = a * b + k + !ERROR: COPYPRIVATE variable 'a' is not PRIVATE or THREADPRIVATE in outer context + !$omp end single copyprivate(a) + !$omp end parallel + !$omp end parallel sections + + print *, a, b + +end program omp_copyprivate Index: flang/test/Semantics/omp-firstprivate01.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-firstprivate01.f90 @@ -0,0 +1,88 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.15.3.4 firstprivate Clause +! Variables that appear in a firstprivate clause on a distribute or +! worksharing constructs must not appear in the private or +! reduction clause in a teams or parallel constructs in the outer context + +program omp_firstprivate + integer :: i, a(10), b(10), c(10) + + a = 10 + b = 20 + + !$omp target + !$omp teams private(a, b) + !ERROR: FIRSTPRIVATE variable 'a' is PRIVATE in outer context + !$omp distribute firstprivate(a) + do i = 1, 10 + a(i) = a(i) + b(i) - i + end do + !$omp end distribute + !$omp end teams + !$omp teams reduction(+:a) + !ERROR: FIRSTPRIVATE variable 'a' is PRIVATE in outer context + !$omp distribute firstprivate(a) + do i = 1, 10 + b(i) = b(i) + a(i) + i + end do + !$omp end distribute + !$omp end teams + !$omp end target + + print *, a, b + + !$omp parallel private(a,b) + !ERROR: FIRSTPRIVATE variable 'b' is PRIVATE in outer context + !$omp do firstprivate(b) + do i = 1, 10 + c(i) = a(i) + b(i) + i + end do + !$omp end do + !$omp end parallel + + !$omp parallel reduction(-:a) + !ERROR: FIRSTPRIVATE variable 'a' is PRIVATE in outer context + !$omp do firstprivate(a,b) + do i = 1, 10 + c(i) = c(i) - a(i) * b(i) * i + end do + !$omp end do + !$omp end parallel + + !$omp parallel reduction(+:a) + !ERROR: FIRSTPRIVATE variable 'a' is PRIVATE in outer context + !$omp sections firstprivate(a, b) + !$omp section + c = c * a + b + !$omp end sections + !$omp end parallel + + !$omp parallel reduction(-:a) + !ERROR: FIRSTPRIVATE variable 'a' is PRIVATE in outer context + !$omp task firstprivate(a,b) + c = c - a * b + !$omp end task + !$omp end parallel + + !$omp parallel reduction(+:b) + !ERROR: FIRSTPRIVATE variable 'b' is PRIVATE in outer context + !$omp taskloop firstprivate(b) + do i = 1, 10 + c(i) = a(i) + b(i) + i + a = a+i + b = b-i + end do + !$omp end taskloop + !$omp end parallel + + !$omp parallel firstprivate(a) + !ERROR: FIRSTPRIVATE variable 'a' is PRIVATE in outer context + !$omp single firstprivate(a) + print *, a + !$omp end single + !$omp end parallel + + print *, c + +end program omp_firstprivate Index: flang/test/Semantics/omp-lastprivate01.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-lastprivate01.f90 @@ -0,0 +1,54 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.15.3.5 lastprivate Clause +! A variable that appears in a lastprivate clause must be definable. + +module protected_var + integer, protected :: p +end module protected_var + +program omp_lastprivate + use protected_var + integer :: i, a(10), b(10), c(10) + integer, parameter :: k = 10 + + a = 10 + b = 20 + + !ERROR: Variable 'k' on the LASTPRIVATE clause is not definable + !$omp parallel do lastprivate(k) + do i = 1, 10 + c(i) = a(i) + b(i) + k + end do + !$omp end parallel do + + !ERROR: Variable 'p' on the LASTPRIVATE clause is not definable + !$omp parallel do lastprivate(p) + do i = 1, 10 + c(i) = a(i) + b(i) + k + end do + !$omp end parallel do + + call omp_lastprivate_sb(i) + + print *, c + +end program omp_lastprivate + +subroutine omp_lastprivate_sb(m) + integer :: i, a(10), b(10), c(10) + integer, intent(in) :: m + + a = 10 + b = 20 + + !ERROR: Variable 'm' on the LASTPRIVATE clause is not definable + !$omp parallel do lastprivate(m) + do i = 1, 10 + c(i) = a(i) + b(i) + m + end do + !$omp end parallel do + + print *, c + +end subroutine omp_lastprivate_sb Index: flang/test/Semantics/omp-lastprivate02.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-lastprivate02.f90 @@ -0,0 +1,35 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.15.3.5 lastprivate Clause +! A list item that is private within a parallel region, or that appears in +! reduction clause of a parallel construct, must not appear in a +! lastprivate clause on a worksharing construct if any of the corresponding +! worksharing regions ever binds to any of the corresponding parallel regions. + +program omp_lastprivate + integer :: a(10), b(10), c(10) + + a = 10 + b = 20 + + !$omp parallel reduction(+:a) + !ERROR: LASTPRIVATE variable 'a' is PRIVATE in outer context + !$omp sections lastprivate(a, b) + !$omp section + c = a + b + !$omp end sections + !$omp end parallel + + !$omp parallel private(a,b) + !ERROR: LASTPRIVATE variable 'a' is PRIVATE in outer context + !ERROR: LASTPRIVATE variable 'b' is PRIVATE in outer context + !$omp do lastprivate(a,b) + do i = 1, 10 + c(i) = a(i) + b(i) + i + end do + !$omp end do + !$omp end parallel + + print *, c + +end program omp_lastprivate Index: flang/test/Semantics/omp-single01.f90 =================================================================== --- flang/test/Semantics/omp-single01.f90 +++ flang/test/Semantics/omp-single01.f90 @@ -1,6 +1,4 @@ ! RUN: %S/test_errors.sh %s %t %f18 -fopenmp -! XFAIL: * - ! OpenMP Version 4.5 ! 2.7.3 single Construct ! Symbol present on multiple clauses @@ -11,7 +9,7 @@ !$omp single private(i) print *, "omp single", i - !ERROR: Symbol ā€˜iā€™ present on multiple clauses + !ERROR: COPYPRIVATE variable 'i' may not appear on a PRIVATE or FIRSTPRIVATE clause on a SINGLE construct !$omp end single copyprivate(i) end program omp_single Index: flang/test/Semantics/omp-single02.f90 =================================================================== --- flang/test/Semantics/omp-single02.f90 +++ flang/test/Semantics/omp-single02.f90 @@ -1,6 +1,4 @@ ! RUN: %S/test_errors.sh %s %t %f18 -fopenmp -! XFAIL: * - ! OpenMP Version 4.5 ! 2.7.3 single Construct ! Copyprivate variable is not thread private or private in outer context @@ -12,7 +10,7 @@ !$omp parallel !$omp single print *, "omp single", i - !ERROR: copyprivate variable ā€˜iā€™ is not threadprivate or private + !ERROR: COPYPRIVATE variable 'i' is not PRIVATE or THREADPRIVATE in outer context !$omp end single copyprivate(i) !$omp end parallel