[Flang][OpenMP] Add semantic checks for OpenMP clauses.

Semantic checks for the following OpenMP 4.5 clauses.

1. 2.15.4.2 - Copyprivate clause
2. 2.15.3.4 - Firstprivate clause
3. 2.15.3.5 - Lastprivate clause

Add related test cases and resolve test cases marked as XFAIL.

Reviewed By: kiranchandramohan

Differential Revision: https://reviews.llvm.org/D91920
This commit is contained in:
Praveen 2021-01-30 22:15:09 +05:30
parent 48ca5d3398
commit 75ef78ffee
14 changed files with 485 additions and 33 deletions

View File

@ -502,7 +502,7 @@ public:
// 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,

View File

@ -209,6 +209,17 @@ protected:
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) {

View File

@ -630,7 +630,6 @@ CHECK_SIMPLE_CLAUSE(Affinity, OMPC_affinity)
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)
@ -655,7 +654,6 @@ CHECK_SIMPLE_CLAUSE(Threadprivate, OMPC_threadprivate)
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)
@ -744,7 +742,40 @@ void OmpStructureChecker::CheckIsVarPartOfAnotherVar(
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;
// Check firstprivate variables in 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));
// Check firstprivate variables in 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));
// Check firstprivate variables in task and taskloop constructs
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) {
@ -975,6 +1006,31 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Depend &x) {
}
}
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);
// Check lastprivate variables in 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));
CheckPrivateSymbolsInOuterCxt(
currSymbols, dirClauseTriple, llvm::omp::Clause::OMPC_lastprivate);
}
llvm::StringRef OmpStructureChecker::getClauseName(llvm::omp::Clause clause) {
return llvm::omp::getOpenMPClauseName(clause);
}
@ -1036,11 +1092,13 @@ void OmpStructureChecker::CheckDependArraySection(
void OmpStructureChecker::CheckIntentInPointer(
const parser::OmpObjectList &objectList, const llvm::omp::Clause clause) {
std::vector<const Symbol *> 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(),
@ -1050,18 +1108,95 @@ void OmpStructureChecker::CheckIntentInPointer(
}
void OmpStructureChecker::GetSymbolsInObjectList(
const parser::OmpObjectList &objectList,
std::vector<const Symbol *> &symbols) {
const parser::OmpObjectList &objectList, SymbolSourceMap &symbols) {
for (const auto &ompObject : objectList.v) {
if (const auto *name{parser::Unwrap<parser::Name>(ompObject)}) {
if (const auto *symbol{name->symbol}) {
if (const auto *commonBlockDetails{
symbol->detailsIf<CommonBlockDetails>()}) {
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) {
// TODO: Replace the hard-coded clause names by using autogen checks or
// a function which maps parser::OmpClause::<name> to the corresponding
// llvm::omp::Clause::OMPC_<name>
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<parser::OmpObjectList>(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());
}
}
}

View File

@ -73,11 +73,22 @@ static OmpDirectiveSet simdSet{Directive::OMPD_distribute_parallel_do_simd,
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 {
// Mapping from 'Symbol' to 'Source' to keep track of the variables
// used in multiple clauses
using SymbolSourceMap = std::multimap<const Symbol *, parser::CharBlock>;
// Multimap to check the triple <current_dir, enclosing_dir, enclosing_clause>
using DirectivesClauseTriple = std::multimap<llvm::omp::Directive,
std::pair<llvm::omp::Directive, const OmpClauseSet>>;
class OmpStructureChecker
: public DirectiveStructureChecker<llvm::omp::Directive, llvm::omp::Clause,
parser::OmpClause, llvm::omp::Clause_enumSize> {
@ -158,8 +169,10 @@ private:
void CheckIsVarPartOfAnotherVar(const parser::OmpObjectList &objList);
void CheckIntentInPointer(
const parser::OmpObjectList &, const llvm::omp::Clause);
void GetSymbolsInObjectList(
const parser::OmpObjectList &, std::vector<const Symbol *> &);
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(

View File

@ -345,6 +345,10 @@ public:
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 @@ private:
Symbol::Flag::OmpThreadprivate};
static constexpr Symbol::Flags dataCopyingAttributeFlags{
Symbol::Flag::OmpCopyIn};
Symbol::Flag::OmpCopyIn, Symbol::Flag::OmpCopyPrivate};
std::vector<const parser::Name *> allocateNames_; // on one directive
SymbolSet privateDataSharingAttributeObjects_; // on one directive
@ -464,7 +468,6 @@ private:
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 @@ private:
sourceLabels_.clear();
targetLabels_.clear();
};
bool HasSymbolInEnclosingScope(const Symbol &, Scope &);
};
template <typename T>
@ -1494,16 +1498,39 @@ void ResolveOmpParts(
void OmpAttributeVisitor::CheckDataCopyingClause(
const parser::Name &name, const Symbol &symbol, Symbol::Flag ompFlag) {
const auto *checkSymbol{&symbol};
if (ompFlag == Symbol::Flag::OmpCopyIn) {
if (const auto *details{symbol.detailsIf<HostAssocDetails>()})
checkSymbol = &details->symbol();
if (const auto *details{symbol.detailsIf<HostAssocDetails>()})
checkSymbol = &details->symbol();
if (ompFlag == Symbol::Flag::OmpCopyIn) {
// List of items/objects that can appear in a 'copyin' clause must be
// 'threadprivate'
if (!checkSymbol->test(Symbol::Flag::OmpThreadprivate))
context_.Say(name.source,
"Non-THREADPRIVATE object '%s' in COPYIN clause"_err_en_US,
checkSymbol->name());
} else if (ompFlag == Symbol::Flag::OmpCopyPrivate &&
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 (!checkSymbol->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());
}
}
}
}
@ -1579,4 +1606,11 @@ void OmpAttributeVisitor::CheckLabelContext(const parser::CharBlock source,
}
}
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

View File

@ -322,6 +322,7 @@ use omp_lib
!$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 @@ use omp_lib
!$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 @@ use omp_lib
! 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 |

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,6 +1,4 @@
! RUN: %S/test_errors.sh %s %t %flang -fopenmp
! XFAIL: *
! RUN: %S/test_errors.sh %s %t %f18 -fopenmp
! OpenMP Version 4.5
! 2.7.3 single Construct
! Symbol present on multiple clauses
@ -11,7 +9,7 @@ program omp_single
!$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

View File

@ -1,6 +1,4 @@
! RUN: %S/test_errors.sh %s %t %flang -fopenmp
! XFAIL: *
! RUN: %S/test_errors.sh %s %t %f18 -fopenmp
! OpenMP Version 4.5
! 2.7.3 single Construct
! Copyprivate variable is not thread private or private in outer context
@ -12,7 +10,7 @@ program omp_single
!$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