Index: flang/include/flang/Semantics/symbol.h =================================================================== --- flang/include/flang/Semantics/symbol.h +++ flang/include/flang/Semantics/symbol.h @@ -504,7 +504,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 @@ -201,6 +201,23 @@ dirContext_.emplace_back(source, dir); } + DirectiveContext *GetEnclosingDirContext() { + CHECK(!dirContext_.empty()); + auto it{dirContext_.rbegin()}; + if (++it != dirContext_.rend()) { + return &(*it); + } + return nullptr; + } + + const PC *FindClauseInContext(C type, DirectiveContext &dirContext) { + auto it{dirContext.clauseInfo.find(type)}; + if (it != dirContext.clauseInfo.end()) { + return it->second; + } + 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 @@ -179,6 +179,14 @@ void CheckDependList(const parser::DataRef &); void CheckDependArraySection( const common::Indirection &, const parser::Name &); + void CheckIntentInPointer( + const parser::OmpObjectList &, const llvm::omp::Clause); + void GetSymbolsInObjectList( + const parser::OmpObjectList &, std::vector &); + void GetSymbolsInDesignatorList( + const std::list &, std::vector &); + void CheckDefinableObjects( + std::vector &, const llvm::omp::Clause); }; } // namespace Fortran::semantics #endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_ Index: flang/lib/Semantics/check-omp-structure.cpp =================================================================== --- flang/lib/Semantics/check-omp-structure.cpp +++ flang/lib/Semantics/check-omp-structure.cpp @@ -360,14 +360,11 @@ // Following clauses do not have a seperate node in parse-tree.h. // They fall under 'struct OmpClause' in parse-tree.h. CHECK_SIMPLE_CLAUSE(Copyin, OMPC_copyin) -CHECK_SIMPLE_CLAUSE(Copyprivate, OMPC_copyprivate) CHECK_SIMPLE_CLAUSE(Device, OMPC_device) CHECK_SIMPLE_CLAUSE(Final, OMPC_final) -CHECK_SIMPLE_CLAUSE(Firstprivate, OMPC_firstprivate) CHECK_SIMPLE_CLAUSE(From, OMPC_from) 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) @@ -599,6 +596,91 @@ } } } +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::Firstprivate &x) { + CheckAllowed(llvm::omp::Clause::OMPC_firstprivate); + + std::vector currSymbols, enclosingSymbols; + GetSymbolsInObjectList(x.v, currSymbols); + + if (GetContext().directive == llvm::omp::Directive::OMPD_distribute || + GetContext().directive == llvm::omp::Directive::OMPD_sections || + GetContext().directive == llvm::omp::Directive::OMPD_do) { + if (auto *enclosingContext{GetEnclosingDirContext()}) { + if (enclosingContext->directive == llvm::omp::Directive::OMPD_teams || + enclosingContext->directive == llvm::omp::Directive::OMPD_parallel) { + if (const auto *clause{FindClauseInContext( + llvm::omp::Clause::OMPC_reduction, *enclosingContext)}) { + const auto &reductionClause{ + std::get(clause->u)}; + const auto &designators{ + std::get>(reductionClause.t)}; + GetSymbolsInDesignatorList(designators, enclosingSymbols); + } else if (const auto *clause{FindClauseInContext( + llvm::omp::Clause::OMPC_private, *enclosingContext)}) { + const auto &privateClause{ + std::get(clause->u)}; + GetSymbolsInObjectList(privateClause.v, enclosingSymbols); + } + if (!enclosingSymbols.empty()) { + for (const auto *symbol : currSymbols) { + auto it{std::find( + enclosingSymbols.begin(), enclosingSymbols.end(), symbol)}; + if (it != enclosingSymbols.end()) { + context_.Say(GetContext().clauseSource, + "FIRSTPRIVATE variable '%s' is PRIVATE in outer context"_err_en_US, + symbol->name()); + } + } + } + } + } + } +} + +void OmpStructureChecker::Enter(const parser::OmpClause::Lastprivate &x) { + CheckAllowed(llvm::omp::Clause::OMPC_lastprivate); + + std::vector currSymbols, enclosingSymbols; + GetSymbolsInObjectList(x.v, currSymbols); + CheckDefinableObjects(currSymbols, llvm::omp::Clause::OMPC_lastprivate); + + if (GetContext().directive == llvm::omp::Directive::OMPD_do || + GetContext().directive == llvm::omp::Directive::OMPD_sections) { + if (auto *enclosingContext{GetEnclosingDirContext()}) { + if (enclosingContext->directive == llvm::omp::Directive::OMPD_parallel) { + if (const auto *clause{FindClauseInContext( + llvm::omp::Clause::OMPC_reduction, *enclosingContext)}) { + const auto &reductionClause{ + std::get(clause->u)}; + const auto &designators{ + std::get>(reductionClause.t)}; + GetSymbolsInDesignatorList(designators, enclosingSymbols); + } else if (const auto *clause{FindClauseInContext( + llvm::omp::Clause::OMPC_private, *enclosingContext)}) { + const auto &privateClause{ + std::get(clause->u)}; + GetSymbolsInObjectList(privateClause.v, enclosingSymbols); + } + if (!enclosingSymbols.empty()) { + for (const auto *symbol : currSymbols) { + auto it{std::find( + enclosingSymbols.begin(), enclosingSymbols.end(), symbol)}; + if (it != enclosingSymbols.end()) { + context_.Say(GetContext().clauseSource, + "LASTPRIVATE variable '%s' is PRIVATE in outer context"_err_en_US, + symbol->name()); + } + } + } + } + } + } +} llvm::StringRef OmpStructureChecker::getClauseName(llvm::omp::Clause clause) { return llvm::omp::getOpenMPClauseName(clause); @@ -659,4 +741,81 @@ } } +void OmpStructureChecker::CheckIntentInPointer( + const parser::OmpObjectList &objectList, const llvm::omp::Clause clause) { + 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()) { + if (IsPointer(*object) && IsIntentIn(*object)) { + context_.Say(name->source, + "Pointer '%s' in the COMMON block with the INTENT(IN) " + "attribute may not appear in a %s clause"_err_en_US, + object->name(), + parser::ToUpperCaseLetters(getClauseName(clause).str())); + } + } + } else { + if (const auto *hostAssocDetails{ + symbol->detailsIf()}) { + symbol = &hostAssocDetails->symbol(); + } + if (IsPointer(*symbol) && IsIntentIn(*symbol)) { + context_.Say(name->source, + "Pointer '%s' with the INTENT(IN) attribute may not appear " + "in a %s clause"_err_en_US, + symbol->name(), + parser::ToUpperCaseLetters(getClauseName(clause).str())); + } + } + } + } + } +} + +void OmpStructureChecker::GetSymbolsInObjectList( + const parser::OmpObjectList &objectList, + std::vector &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()); + } + } else { + symbols.emplace_back(&symbol->GetUltimate()); + } + } + } + } +} + +void OmpStructureChecker::GetSymbolsInDesignatorList( + const std::list &designatorList, + std::vector &symbols) { + for (const auto &designator : designatorList) { + if (const auto *name{parser::Unwrap(designator)}) { + if (const auto *symbol{name->symbol}) { + symbols.emplace_back(&symbol->GetUltimate()); + } + } + } +} + +void OmpStructureChecker::CheckDefinableObjects( + std::vector &symbols, const llvm::omp::Clause clause) { + for (const auto *symbol : symbols) { + if (!IsVariableName(*symbol)) { + context_.Say(GetContext().clauseSource, + "Variable '%s' on the %s clause is not definable"_err_en_US, + symbol->name(), + parser::ToUpperCaseLetters(getClauseName(clause).str())); + } + } +} + } // namespace Fortran::semantics Index: flang/lib/Semantics/resolve-directives.cpp =================================================================== --- flang/lib/Semantics/resolve-directives.cpp +++ flang/lib/Semantics/resolve-directives.cpp @@ -282,6 +282,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 @@ -326,7 +330,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 @@ -362,6 +366,7 @@ void CheckDataCopyingClause( const parser::Name &, const Symbol &, Symbol::Flag); + bool HasSymbolInEnclosingScope(const Symbol &, Scope &); }; template @@ -1171,7 +1176,34 @@ context_.Say(name.source, "Non-THREADPRIVATE object '%s' in COPYIN clause"_err_en_US, checkSymbol->name()); + } else { + // 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)) { + 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()); + } + } } } +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 @@ -321,6 +321,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 @@ -336,6 +337,7 @@ !$omp workshare num_threads(4) a = 1.0 !ERROR: COPYPRIVATE clause is not allowed on the END WORKSHARE directive + !ERROR: COPYPRIVATE variable 'a' is not PRIVATE or THREADPRIVATE in outer context !$omp end workshare nowait copyprivate(a) !$omp end parallel 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 private(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,22 @@ +! 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), k + + a = 10 + k = 10 + + !$omp parallel + !$omp single + a = a + k + !ERROR: COPYPRIVATE variable 'k' is not PRIVATE or THREADPRIVATE in outer context + !$omp end single copyprivate(k) + !$omp end parallel + + print *, a + +end program omp_copyprivate Index: flang/test/Semantics/omp-copyprivate03.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-copyprivate03.f90 @@ -0,0 +1,31 @@ +! 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 end parallel + + !$omp parallel + !$omp single + b = b - a + !ERROR: COPYPRIVATE variable 'a' is not PRIVATE or THREADPRIVATE in outer context + !$omp end single copyprivate(a) + !$omp end parallel + + print *, a, b + +end program omp_copyprivate Index: flang/test/Semantics/omp-copyprivate04.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-copyprivate04.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-copyprivate05.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-copyprivate05.f90 @@ -0,0 +1,25 @@ +! 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), k + + a = 10 + k = 10 + + !$omp parallel sections private(k) + !$omp section + !$omp parallel + !$omp single + a = a + k + !ERROR: COPYPRIVATE variable 'k' is not PRIVATE or THREADPRIVATE in outer context + !$omp end single copyprivate(k) + !$omp end parallel + !$omp end parallel sections + + print *, a + +end program omp_copyprivate Index: flang/test/Semantics/omp-firstprivate01.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-firstprivate01.f90 @@ -0,0 +1,29 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.15.3.4 firstprivate Clause +! A list item that is private within a teams region must not appear in a +! firstprivate clause on a distribute construct if any of the distribute +! regions arising from the distribute construct ever bind to any of the +! teams regions arising from the teams construct. + +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 + c(i) = a(i) + b(i) - i + end do + !$omp end distribute + !$omp end teams + !$omp end target + + print *, c + +end program omp_firstprivate Index: flang/test/Semantics/omp-firstprivate02.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-firstprivate02.f90 @@ -0,0 +1,29 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.15.3.4 firstprivate Clause +! A list item that appears in a reduction clause of a teams construct must +! not appear in a firstprivate clause on a distribute construct if any of +! the distribute regions arising from the distribute construct ever bind +! to any of the teams regions arising from the teams construct. + +program omp_firstprivate + + integer :: i, a(10), b(10), c(10) + + a = 10 + b = 20 + + !$omp target + !$omp teams reduction(+:a) + !ERROR: FIRSTPRIVATE variable 'a' is PRIVATE in outer context + !$omp distribute firstprivate(a) + do i = 1, 10 + c(i) = a(i) + b(i) + i + end do + !$omp end distribute + !$omp end teams + !$omp end target + + print *, c + +end program omp_firstprivate Index: flang/test/Semantics/omp-firstprivate03.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-firstprivate03.f90 @@ -0,0 +1,36 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.15.3.4 firstprivate Clause +! A list item that appears in a reduction clause of a parallel construct +! must not appear in a firstprivate clause on a worksharing construct if +! any of the worksharing or task regions arising from the worksharing construct +! ever bind to any of the parallel regions arising from the parallel construct. + +program omp_firstprivate + + integer :: i, a(10), b(10), c(10) + + a = 10 + b = 20 + + !$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 + + print *, c + +end program omp_firstprivate Index: flang/test/Semantics/omp-firstprivate04.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-firstprivate04.f90 @@ -0,0 +1,29 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.15.3.4 firstprivate Clause +! A list item that appears in a reduction clause of a parallel construct +! must not appear in a firstprivate clause on a worksharing construct if +! any of the worksharing or task regions arising from the worksharing construct +! ever bind to any of the parallel regions arising from the parallel construct. + +module test + integer :: a(10), b(10), c(10) +end module test + +program omp_firstprivate + use test + + a = 10 + b = 20 + + !$omp parallel reduction(+:a) + !ERROR: FIRSTPRIVATE variable 'a' is PRIVATE in outer context + !$omp sections firstprivate(a, b) + !$omp section + c = a + b + !$omp end sections + !$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,23 @@ +! 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. + +program omp_lastprivate + + 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 + + print *, c + +end program omp_lastprivate Index: flang/test/Semantics/omp-lastprivate02.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-lastprivate02.f90 @@ -0,0 +1,26 @@ +! 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 + + print *, c + +end program omp_lastprivate Index: flang/test/Semantics/omp-lastprivate03.f90 =================================================================== --- /dev/null +++ flang/test/Semantics/omp-lastprivate03.f90 @@ -0,0 +1,28 @@ +! 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 :: i, a(10), b(10), c(10) + + a = 10 + b = 20 + + !$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